У меня есть класс Java с тысячей методов строки если/еще логика как это:
if (userType == "admin") {
if (age > 12) {
if (location == "USA") {
// do stuff
} else if (location == "Mexico") {
// do something slightly different than the US case
}
} else if (age < 12 && age > 4) {
if (location == "USA") {
// do something slightly different than the age > 12 US case
} else if (location == "Mexico") {
// do something slightly different
}
}
} else if (userType == "student") {
if (age > 12) {
if (location == "USA") {
// do stuff
} else if (location == "Mexico") {
// do something slightly different than the US case
}
} else if (age < 12 && age > 4) {
if (location == "USA") {
// do something slightly different than the age > 12 US case
} else if (location == "Mexico") {
// do something slightly different
}
}
Как я должен осуществить рефакторинг это во что-то более managable?
Риск заключается не только в том, что это некрасиво, но и в том, что это очень подвержено ошибкам. Через некоторое время вы можете столкнуться с риском совпадения ваших условий.
Если вы действительно можете различить условие по типу пользователя, вы можете как минимум разбить тело каждого условия на отдельную функцию. Так что вы проверяете на основе типа и вызываете соответствующую функцию, специфичную для этого типа. Еще одно объектно-ориентированное решение - представить каждого пользователя как класс, а затем переопределить какой-либо метод расчета, чтобы вернуть значение, основанное на возрасте. Если вы не можете использовать классы, но можете, по крайней мере, использовать перечисления, тогда вы сможете сделать более удобный оператор switch для перечислений. Переключатели на строки появятся только в Java 7.
Меня беспокоят ситуации перекрытия (например, два типа пользователей с некоторыми общими правилами и т. Д.). Если это в конечном итоге так, вам может быть лучше представить данные в виде некоторого внешнего файла (например, таблицы), который вы будете читать и поддерживать, и ваш код по существу будет работать как драйвер, который выполняет соответствующий поиск в этих данных. установленный. Это общий подход для сложных бизнес-правил, поскольку никто не хочет поддерживать тонны кода.
Первое, что я сделал бы с этим кодом, - это создал бы типы Admin
и Student
, оба из которых наследуются от базового типа User
. Эти классы должны иметь метод doStuff ()
, в котором вы скрываете остальную часть этой логики.
Как показывает практика, каждый раз, когда вы ловите себя на переключении типа, вы можете вместо этого использовать полиморфизм.
Используйте концепции ООП:
Это зависит от остальной части дизайна, но, возможно, вам понадобится пользовательский
интерфейс, Student
, Admin
интерфейсы расширяет его и UsaStudent
, MexicoStudent
, UsaAdmin
, MexicoAdmin
реализации, которые делают некоторые вещи. Сохраните экземпляр User
и просто вызовите его метод doStuff
.
Взгляните на паттерн Посетитель. Он использует полиморфизм, но является немного более гибким, так как позже легче добавлять новые случаи.
Обратной стороной является необходимость преобразования информации о состоянии в разные экземпляры. Преимущество - более чистый способ добавления поведения без изменения иерархии наследования.
Основываясь только на именах переменных, я предполагаю, что вы должны подклассифицировать User
(или что бы это ни было, что имеет переменную userType
) в AdminUser
и StudentUser
(и, возможно, другие) и использовать полиморфизм.
Если код в блоках вписывается в несколько стандартных шаблонов, я бы создал таблицу с колонками (type, location, minAge, maxAge, action), где 'action' - это перечисление, указывающее, какой из нескольких типов обработки нужно выполнить. В идеале эта таблица должна считываться из файла данных или храниться в SQL.
Тогда вы можете просто выполнить поиск по таблице в коде Java, чтобы определить действие, которое нужно предпринять для пользователя.
без дополнительной информации нет хорошего ответа
но справедливое предположение будет таким: используйте ОО
сначала определите пользователя, определите администратора, студента и все остальные типы пользователей, а затем позвольте полиморфизму позаботиться об остальном
.Я бы, наверное, сначала проверил, можно ли параметризовать код doStuff и doSimilarStuff.
Первое - используйте перечисления для userType и location - тогда вы сможете использовать операторы switch (улучшает читаемость)
Второе - используйте больше методов.
Пример:
switch (userType) {
case Admin: handleAdmin(); break;
case Student: handleStudent(); break;
}
и позже
private void handleAdmin() {
switch (location) {
case USA: handleAdminInUSA(); break;
case Mexico: handleAdminInMexico(); break;
}
}
Далее, определите дублирующийся код и поместите его в дополнительные методы.
EDIT
Если кто-то заставляет вас писать на Java без перечислений (например, вас заставляют использовать Java 1.4.2), используйте 'final static' вместо перечислений или сделайте что-то вроде:
if (isAdmin(userType)) {
handleAdmin(location, age);
} else if (isStudent(userType)) {
handleStudent(location, age));
}
//...
private void handleAdmin(String location, int age) {
if (isUSA(location)) {
handleAdminInUSA(age);
} else if (isUSA(location)) {
handleAdminInMexico(age);
}
}
//...
private void handleAdminInUSA(int age) {
if (isOldEnough(age)) {
handleAdminInUSAOldEnough();
} else if (isChild(age)) {
handleChildishAdminInUSA(); // ;-)
} //...
}
Thousands? Возможно, движок правил - это то, что вам нужно. Drools может быть жизнеспособной альтернативой.
Или шаблон Command, который инкапсулирует всю логику "сделать что-то немного другое" для каждого случая. Храните каждую команду в карте с конкатенацией возраста, местоположения и других факторов в качестве ключа. Найдите команду, выполните ее, и все готово. Красиво и чисто.
Карта может храниться в виде конфигурации и считываться при запуске. Вы можете добавить новую логику, добавив новые классы и изменив конфигурацию.
Вы можете использовать шаблон «Цепочка ответственности».
Рефакторинг операторов if-else
в классы, например, с интерфейсом IUserController
.
Инициализируйте свою цепочку в списке, дереве или любой подходящей структуре данных и выполните желаемые функции в этой цепочке. Вы можете использовать шаблон Builder для создания упомянутой структуры данных. Он похож на шаблон стратегии, но в шаблоне цепочки ответственности экземпляр в цепочке может вызывать связанные экземпляры.
Кроме того, вы можете смоделировать функциональность, зависящую от местоположения, с помощью шаблона стратегии. Надеюсь, это поможет.
Вам действительно нужно разбить эти случаи на методы объекта. Я предполагаю, что эти строки и числа извлекаются из базы данных. Вместо того, чтобы использовать их в исходной форме в гигантской вложенной условной логике, вам нужно использовать эти фрагменты данных для создания объектов, моделирующих желаемые взаимодействия. Рассмотрим класс UserRole с подклассами StudentRole и AdminRole, класс Region с подклассами USA и Mexico и класс AgeGroup с соответствующими секционированными подклассами.
Как только у вас будет эта объектно-ориентированная структура, вы сможете использовать хорошо понятные объектно-ориентированные шаблоны проектирования, чтобы изменить эту логику.
Вы должны использовать Стратегии , возможно, реализованные в перечислении, например:
enum UserType {
ADMIN() {
public void doStuff() {
// do stuff the Admin way
}
},
STUDENT {
public void doStuff() {
// do stuff the Student way
}
};
public abstract void doStuff();
}
В качестве структуры кода внутри каждой внешней ветви if
в вашем коде выглядит почти так же, на следующем этапе рефакторинга вы, возможно, захотите исключить это дублирование с помощью шаблонных методов . В качестве альтернативы вы можете превратить местоположение (и, возможно, возраст) в стратегию.
Обновление: в Java4 вы можете реализовать типизированное перечисление вручную и использовать простое старое создание подклассов для реализации различных стратегий.
Вы можете сделать userType
перечислением
и дать ему метод, который будет выполнять все ваши действия «сделать что-то немного другое».