Подтвердить что ты не робот

Рефакторинг if/else логики

У меня есть класс java с методом тысячи строк if/else, например:

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
          }
     }

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

4b9b3361

Ответ 1

Вы должны использовать Стратегии, возможно, реализованные в перечислении, например:

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, вы можете реализовать имя перечисления вручную и использовать обычное старое подклассов для реализации различных стратегий.

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

Первичные перечисления для 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;
  }
}

Далее укажите идентификационный код и добавьте дополнительные методы.

ИЗМЕНИТЬ

Если кто-то заставляет вас кодировать Java без перечислений (например, вы вынуждены использовать Java 1.4.2), используйте "final static вместо enums" или выполните что-то вроде:

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

Ответ 5

Вы можете сделать userType a enum и дать ему метод, который выполняет все ваши действия "делать что-то несколько другое".

Ответ 6

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

но справедливое предположение было бы следующим: используйте OO

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

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

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

Ответ 10

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

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

Ответ 11

Вы можете использовать шаблон цепочки ответственности.

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

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

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

Ответ 12

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

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

Ответ 13

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

Ответ 14

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

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