Логотип ConstructiCat
CodeBust.
Навигация по разделу ▾

Замена подкласса полями.

Проблема

У вас есть подклассы, которые отличаются только методами, возвращающими данные-константы.

Решение

Замените методы полями в родительском классе и удалите подклассы.

##Пример

До
abstract class Person {
  abstract boolean isMale();
  abstract char getCode();
}
class Male extends Person {
  boolean isMale() { return true; }
  char getCode() { return 'M'; }
}
class Female extends Person {
  boolean isMale() { return false; }
  char getCode() { return 'F'; }
}
После
class Person {
  private final boolean male;
  private final char code;

  private Person(boolean male, char code) {
    this.male = male;
    this.code = code;
  }
  static Person createMale() { return new Person(true, 'M'); }
  static Person createFemale() { return new Person(false, 'F'); }
  boolean isMale() { return male; }
  char getCode() { return code; }
}

##Зачем делать рефакторинг

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

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

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

##Преимущества

  • Упрощает архитектуру системы. Создание подклассов — слишком избыточное решение, если все, что нужно сделать, это возвращать разные значения в нескольких методах.

##Как делать рефакторинг

  1. Примените к подклассам замену конструктора фабричным методом.

  2. Замените вызовы конструкторов подклассов вызовами фабричного метода суперкласса.

  3. Объявите в суперклассе поля для хранения значений каждого из методов подклассов, возвращающих константные значения.

  4. Создайте защищённый конструктор суперкласса для инициализации новых полей.

  5. Создайте или модифицируйте имеющиеся конструкторы подклассов, чтобы они вызывали новый конструктор родительского класса и передавали в него соответствующие значения.

  6. Реализуйте каждый константный метод в родительском классе так, чтобы он возвращал значение соответствующего поля, а затем удалите метод из подкласса.

  7. Если конструктор подкласса имеет какую-то дополнительную функциональность, примените встраивание метода для встраивания его конструктора в фабричный метод суперкласса.

  8. Удалите подкласс.