Также известен как Introduce Foreign Method

Рефакторинг Введение внешнего метода

Проблема

Служебный класс не содержит метода, который вам нужен, при этом у вас нет возможности добавить метод в этот класс.

Решение

Добавьте метод в клиентский класс и передавайте в него объект служебного класса в качестве аргумента.

До
class Report {
  //...
  void sendReport() {
    Date nextDay = new Date(previousEnd.getYear(),
      previousEnd.getMonth(), previousEnd.getDate() + 1);
    //...
  }
}
После
class Report {
  //...
  void sendReport() {
    Date newStart = nextDay(previousEnd);
    //...
  }
  private static Date nextDay(Date arg) {
    return new Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1);
  }
}
До
class Report 
{
  //...
  void SendReport() 
  {
    DateTime nextDay = previousEnd.AddDays(1);
    //...
  }
}
После
class Report 
{
  //...
  void SendReport() 
  {
    DateTime nextDay = NextDay(previousEnd);
    //...
  }
  private static DateTime NextDay(DateTime date) 
  {
    return date.AddDays(1);
  }
}
До
class Report {
  //...
  function sendReport() {
    $previousDate = clone $this->previousDate;
    $paymentDate = $previousDate->modify('+7 days');
    //...
  }
}
После
class Report {
  //...
  function sendReport() {
    $paymentDate = $this->nextWeek($this->previousDate);
    //...
  }
  /**
   * Foreign method. Should be in Date.
   */
  private static function nextWeek(DateTime $arg) {
    $previousDate = clone $arg;
    return $previousDate->modify('+7 days');
  }
}
До
class Report:
    #...
    def sendReport(self):
        nextDay = Date(self.previousEnd.getYear(),
            self.previousEnd.getMonth(), self.previousEnd.getDate() + 1);
        #...
После
class Report:
    #...
    def sendReport(self):
        newStart = self._nextDay(self.previousEnd)
        #...
        
    def _nextDay(self, arg):
        return Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1)

Причины рефакторинга

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

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

Так как вы передаёте объект служебного класса в параметры нового метода, у вас есть доступ ко всем его полям. Вы можете делать внутри этого метода практически все, что вам может потребоваться, как если бы метод был частью служебного класса.

Достоинства

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

Недостатки

  • Причины того, почему метод служебного класса находится в клиентском классе, не всегда очевидны для того специалиста, который будет поддерживать код после вас. Если данный метод может быть использован и в других классах, имеет смысл создать обёртку над служебным классом, и поместить метод туда. То же самое имеет смысл сделать, если таких служебных методов несколько. В этом поможет рефакторинг введение локального расширения.

Порядок рефакторинга

  1. Создайте новый метод в клиентском классе.

  2. В этом методе создайте параметр, в который будет передаваться объект служебного класса. Если этот объект может быть получен из клиентского класса, параметр можно не создавать.

  3. Извлеките волнующие вас участки кода в этот метод и замените их вызовами метода.

  4. Обязательно оставьте в комментарии к этому методу метку Foreign method и призыв поместить этот метод в служебный класс, если такая возможность появится в дальнейшем. Это облегчит понимание того, почему этот метод находится в данном классе для тех, кто будет поддерживать программный продукт в будущем.

Устали читать?

Сбегайте за подушкой, у нас тут контента на 7 часов чтения.

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

Узнать больше...