2010-05-26 2 views
33

У меня есть класс 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 
      } 
    } 

Как я должен реорганизовать это в чем-то более управляемым?

+18

Я понимаю, что это быстрый пример, но сравнение строк действительно нужно делать с помощью 'equals()'. – BalusC

+14

... что происходит, когда вы ровно 12 ??? – polygenelubricants

+2

Я бы взглянул на рисунок декоратора http://en.wikipedia.org/wiki/Decorator_pattern. – Lumpy

ответ

1

Вы можете сделать userTypeenum и дать ему метод, который выполняет все ваши действия «делайте что-то несколько другое».

24

Вы должны использовать Strategies, возможно, реализуется в рамках перечисления, например:

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 ветви в коде выглядит так же, в следующем шаге рефакторинга вы могли бы хотите разделить это дублирование, используя template methods. В качестве альтернативы, вы также можете включить (и, возможно, возраст) в стратегию.

Обновление: В Java4 вы можете реализовать typesafe enum вручную и использовать обычное старое подклассов для реализации различных стратегий.

1

без дополнительной информации нет хорошего ответа

но справедливо предположение было бы это: использование OO

сначала определить пользователя, определить Администратор, студент и все другие типы пользователей, а затем пусть полиморфизм заботиться из

отдыха
1

Основываясь только на имена переменных, я предполагаю, что вы должны создать подкласс User (или что-то, что имеет переменную userType) в AdminUser и StudentUser (и, возможно, другие) и использовать polymorphism.

5

Первое - использование перечислений для UserType и местоположения - то вы можете использовать операторы переключения (улучшает читаемость)

Второй - использовать несколько методов.

Пример:

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), используйте «окончательной статики вместо перечислений или сделать что-то вроде:

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(); // ;-) 
    } //... 
} 
+0

Забыл упомянуть, что это приложение java 4 -> нет перечислений – David

+0

Я бы создал перечисление для ageGroup: INFANT, CHILD, OVERTWELVE. – DJClayworth

+0

@ Давид - сделай это старомодно; например используя HashMap для сопоставления строк userType с целыми константами, а затем включения целочисленных констант. –

1

Риск этого не только в том, что он неприглядный, но и в том, что он очень подвержен ошибкам. Через некоторое время вы можете столкнуться с риском совпадений в ваших условиях.

Если вы действительно можете отличить условие по типу пользователя, вы можете как минимум разбить тело каждого условия на отдельную функцию.Таким образом, вы проверяете на основе типа и вызываете соответствующую функцию, специфичную для этого типа. Более OO-решение должно представлять каждого пользователя как класс, а затем переопределять некоторый метод расчета, чтобы вернуть значение в зависимости от возраста. Если вы не можете использовать классы, но можете хотя бы использовать перечисления, тогда вы сможете сделать более приятный оператор switch в перечислениях. Переключатели на Strings будут доступны только в Java 7.

Меня беспокоят ситуации перекрытий (например, два пользовательских типа с некоторыми общими правилами и т. Д.). Если это произойдет, вам может быть лучше представить данные как некоторый внешний файл (например, таблицу), который вы будете читать и обслуживать, и ваш код будет по существу работать как драйвер, который выполняет соответствующий поиск в этих данных задавать. Это общий подход для сложных бизнес-правил, поскольку никто не хочет идти и поддерживать тонны кода.

12

Первое, что я сделал бы с этим кодом, это создать типы Admin и Student, оба из которых наследуют от базового типа User. Эти классы должны иметь метод doStuff(), где вы скрываете остальную часть этой логики.

Как правило, в любое время, когда вы включаете тип включения, вы можете использовать полиморфизм.

1

Я бы, наверное, сначала проверил, можете ли вы параметризовать код doStuff и doSimilarStuff.

9

Тысячи? Возможно, вам нужен механизм правил. Дрослы могут быть жизнеспособной альтернативой.

Или шаблон команды, который инкапсулирует все «делать что-то немного отличающееся» для каждого случая. Храните каждую команду на карте с совпадением возраста, местоположения и других факторов в качестве ключа. Найдите команду, выполните ее, и все готово. Хороший и чистый.

Карта может храниться как конфигурация и считываться при запуске. Вы можете добавить новую логику, добавив новые классы и переконфигурируя.

+0

+1 для просмотра в модуле правил. Если у вас тысячи правил, они значительно ускорят выполнение и управление. –

0

Использование ООП понятия: Это зависит от остальной части дизайна, но, возможно, вы должны иметь интерфейс user, Student, Admin интерфейсов на расширяет его и UsaStudent, MexicoStudent, UsaAdmin, MexicoAdmin реализацию, сделать некоторые вещи. Возьмите экземпляр User и просто позвоните по его методу doStuff.

+0

Этот способ вместо тысячи строк «if-then-else» вы найдете свое «я» с тысячами классов со сложными отношениями наследования. –

+0

@Artem Barger Я предпочитаю много маленьких занятий по нескольким очень длинным методам. –

+0

, определяя множество небольших классов, вы просто удаляете код спагетти из одного места в другое, ведь после того, как вы прочитаете ввод, вам нужно будет решить, какой экземпляр будет создан, поэтому вы сделаете это в своем заводском классе или что-то в этом роде. –

1

Взгляните на шаблон посетителя. Он использует полиморфизм, но немного более гибкий, поскольку легче добавлять новые случаи позже.

Недостатком является то, что вам нужно каким-то образом преобразовать информацию о состоянии в разные экземпляры. Преимущество - более чистый способ добавить поведение, не изменяя иерархию наследования.

1

Вы можете использовать шаблон Chain of Responsibility.

Рефакторинг if-else инструкций в классах с интерфейсом IUserController, например.

Инициализируйте свою цепочку в списке или дереве или любой подходящей структуре данных и выполните необходимые функции в этой цепочке. Вы можете использовать шаблон Builder для создания указанной структуры данных. Он похож на шаблон стратегии, но в цепочке шаблонов ответственности экземпляр в цепочке может вызывать связанные экземпляры (ы).

Кроме того, вы можете моделировать специфику местоположения, используя шаблон стратегии. Надеюсь, поможет.

1

Если код в блоках соответствует нескольким стандартным шаблонам, я бы создал таблицу со столбцами (тип, местоположение, minAge, maxAge, действие), где «действие» - это перечисление, указывающее, какой из нескольких типов обработки делать. В идеале эта таблица будет считана из файла данных или хранится в SQL.

Затем вы можете просто выполнить поиск таблицы в коде Java, чтобы определить действие, которое требуется выполнить для пользователя.

-1

Вам действительно нужно разбить эти случаи на методы объектов. Я предполагаю, что эти строки и числа выводятся из базы данных. Вместо того, чтобы использовать их в своей необработанной форме в гигантской вложенной условной логике, вам нужно использовать эти данные для построения объектов, которые моделируют желаемые взаимодействия. Рассмотрим класс UserRole с подклассами StudentRole и AdminRole, классом Region с подклассами США и Мексики и классом AgeGroup с соответствующими секционированными подклассами.

После того, как вы создадите эту объектно-ориентированную структуру, вы сможете использовать хорошо понятые объектно-ориентированные шаблоны проектирования, чтобы перефразировать эту логику.

Смежные вопросы