Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

Приёмы рефакторинга. Перемещение методов между классами

Лекция



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

Если вы разместили функциональность по классам не самым удачным образом — это еще не повод отчаиваться.

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

Перемещение метода

Проблема: Метод используется в другом классе больше, чем в собственном.

Решение: Создайте новый метод в классе, который использует его больше других, и перенесите туда код из старого метода. Код оригинального метода превратите в обращение к новому методу в другом классе либо уберите его вообще.

Перемещение поля

Проблема: Поле используется в другом классе больше, чем в собственном.

Решение: Создайте поле в новом классе и перенаправьте к нему всех пользователей старого поля.

Извлечение класса

Проблема: Один класс работает за двоих.

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

Встраивание класса

Проблема: Класс почти ничего не делает, ни за что не отвечает, и никакой ответственности для этого класса не планируется.

Решение: Переместите все фичи из описанного класса в другой.

Сокрытие делегирования

Проблема: Клиент получает объект B из поля или метода объекта А. Затем клиент вызывает какой-то метод объекта B.

Решение: Создайте новый метод в классе А, который бы делегировал вызов объекту B. Таким образом, клиент перестанет знать о классе В и зависеть от него.

Удаление посредника

Проблема: Класс имеет слишком много методов, которые просто делегируют работу другим объектам.

Решение: Удалите эти методы и заставьте клиента вызывать конечные методы напрямую.

Введение внешнего метода

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

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

Введение локального расширения

Проблема: В служебном классе отсутствуют некоторые методы, которые вам нужны. При этом добавить их в этот класс вы не можете.

Решение: Создайте новый класс, который бы содержал эти методы, и сделайте его наследником служебного класса, либо его оберткой.

же известен как:Move Method

Рефакторинг Перемещение метода

Проблема

Метод используется в другом классе больше, чем в собственном.

Решение

Создайте новый метод в классе, который использует его больше других, и перенесите туда код из старого метода. Код оригинального метода превратите в обращение к новому методу в другом классе либо уберите его вообще.

Приёмы рефакторинга. Перемещение методов между классами

Приёмы рефакторинга. Перемещение методов между классами

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

  1. Вы хотите переместить метод в класс, который содержит данные, с которыми, в основном, работает этот метод. Этим вы увеличиваете связность внутри классов.

  2. Вы хотите переместить метод, чтобы убрать или уменьшить зависимость класса, вызывающего этот метод, от класса, в котором он находился. Это может быть полезно, если вызывающий класс уже имеет зависимость от класса, куда вы планируете перенести метод. Таким образом, вы уменьшаете связанность между классами.

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

  1. Проверьте все фичи, используемые старым методом в его же классе. Возможно, их тоже следует переместить. Руководствуйтесь таким правилом — если фича используется только интересующим вас методом, ее точно следует переносить. Если фича используется и другими методами, возможно, следует перенести и эти методы. Иногда гораздо проще перенести пачку методов, чем настраивать взаимодействие между ними в разных классах.

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

  2. Объявите новый метод в классе-приемнике. Возможно, следует придумать для метода новое имя, которое в новом классе будет подходить ему больше.

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

    Теперь у вас есть способ обратиться к объекту-получателю и новый метод в его классе. С этим всем вы уже можете превратить старый метод в обращение к новому методу.

  4. Оцените, есть ли возможность удалить старый метод вообще? При этом нужно будет во всех местах, где используется этот метод, поставить обращение к новому.

Также известен как:Move Field

Рефакторинг Перемещение поля

Проблема

Поле используется в другом классе больше, чем в собственном.

Решение

Создайте поле в новом классе и перенаправьте к нему всех пользователей старого поля.

Приёмы рефакторинга. Перемещение методов между классами

Приёмы рефакторинга. Перемещение методов между классами

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

Зачастую поля переносятся как часть извлечение одного класса из другого. Решить, в каком из классов должно остаться поле, бывает непросто. Тем не менее, у нас есть неплохой рецепт — поле должно быть там, где находятся методы, которые его используют(либо там, где этих методов больше).

Это правило поможет вам и в других случаях, когда поле попросту находится не там, где нужно.

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

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

  2. Создайте такое же поле с методами доступа в классе-приемнике.

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

  4. Замените все обращения к старому полю на соответствующие вызовы методов в классе-получателе. Если поле не приватное, проделайте это и в суперклассе, и в подклассах.

  5. Удалите поле в исходном классе.

Родственные рефакторинги

Перемещение поля

Помогает рефакторингу

Извлечение класса

Встраивание класса

Борется с запахом

Стрельба дробью

Параллельные иерархии наследования

Неуместная близость

Также известен как:Extract Class

Рефакторинг Извлечение класса

Проблема

Один класс работает за двоих.

Решение

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

Приёмы рефакторинга. Перемещение методов между классами

Приёмы рефакторинга. Перемещение методов между классами

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

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

Достоинства

  • Этот рефакторинг призван помочь в соблюдении принципа единственной обязанности класса. Это делает код ваших классов очевиднее и понятнее.

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

Недостатки

  • Если при проведении этого рефакторинга вы перестараетесь, придется прибегнуть к встраиванию класса.

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

Перед началом рефакторинга обязательно определите, как именно следует разделить обязанности класса.

  1. Создайте новый класс, который будет содержать выделенную функциональность.

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

  3. Используйте перемещение поля и перемещение метода для каждого поля и метода, которые вы решили переместить в новый класс. Для методов имеет смысл начинать с приватных, таким образом вы снижаете вероятность допустить массу ошибок. Старайтесь двигаться понемногу и тестировать результат после каждого перемещения, это избавит вас от необходимости исправлять большое число ошибок в самом конце.

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

  4. Еще одним нюансом является доступность нового класса извне. Об этом говорит сайт https://intellect.icu . Вы можете полностью спрятать его от клиента, сделав приватным, управляя при этом его полями из старого класса. Либо сделать его публичным, предоставив клиенту возможность напрямую менять значения. Решение зависит от того, насколько безопасны для поведения старого класса будут неожиданные прямые изменения значений в новом классе.

Анти-рефакторинг

Встраивание класса

Родственные рефакторинги

Извлечение подкласса

Замена простого поля объектом

Борется с запахом

Дублирование кода

Большой класс

Расходящиеся модификации

Группы данных

Одержимость элементарными типами

Временное поле

Неуместная близость

Также известен как:Inline Class

Рефакторинг Встраивание класса

Проблема

Класс почти ничего не делает, ни за что не отвечает, и никакой ответственности для этого класса не планируется.

Решение

Переместите все фичи из описанного класса в другой.

Приёмы рефакторинга. Перемещение методов между классами

Приёмы рефакторинга. Перемещение методов между классами

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

Часто этот рефакторинг оказывается следствием недавнего «переселения» части фич класса в другие, после чего от исходного класса мало что осталось.

Достоинства

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

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

  1. Создайте в классе-приемнике публичные поля и методы, которые есть в классе-доноре. Методы должны обращаться к аналогичным методам класса-донора.

  2. Замените все обращения к классу-донору обращениями к полям и методам класса-приемника.

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

  4. Удалите исходный класс.

Анти-рефакторинг

Извлечение класса

Борется с запахом

Стрельба дробью

Ленивый класс

Теоретическая общность

Также известен как:Hide Delegate

Рефакторинг Сокрытие делегирования

Проблема

Клиент получает объект B из поля или метода объекта А. Затем клиент вызывает какой-то метод объекта B.

Решение

Создайте новый метод в классе А, который бы делегировал вызов объекту B. Таким образом, клиент перестанет знать о классе В и зависеть от него.

Приёмы рефакторинга. Перемещение методов между классами

Приёмы рефакторинга. Перемещение методов между классами

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

Для начала следует определиться с названиями:

  • Сервер — это объект, к которому клиент имеет непосредственный доступ.

  • Делегат — это конечный объект, который содержит функциональность, нужную клиенту.

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

Достоинства

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

Недостатки

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

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

  1. Для каждого метода класса-делегата, вызываемого клиентом, нужно создать метод в классе-сервере, который бы делегировал вызов классу-делегату.

  2. Измените код клиента так, чтобы он вызывал методы класса-сервера.

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

Анти-рефакторинг

Удаление посредника

Борется с запахом

Цепочка вызовов

Неуместная близость

Также известен как:Move Field

Рефакторинг Перемещение поля

Проблема

Поле используется в другом классе больше, чем в собственном.

Решение

Создайте поле в новом классе и перенаправьте к нему всех пользователей старого поля.

Приёмы рефакторинга. Перемещение методов между классами

Приёмы рефакторинга. Перемещение методов между классами

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

Зачастую поля переносятся как часть извлечение одного класса из другого. Решить, в каком из классов должно остаться поле, бывает непросто. Тем не менее, у нас есть неплохой рецепт — поле должно быть там, где находятся методы, которые его используют(либо там, где этих методов больше).

Это правило поможет вам и в других случаях, когда поле попросту находится не там, где нужно.

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

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

  2. Создайте такое же поле с методами доступа в классе-приемнике.

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

  4. Замените все обращения к старому полю на соответствующие вызовы методов в классе-получателе. Если поле не приватное, проделайте это и в суперклассе, и в подклассах.

  5. Удалите поле в исходном классе.

Родственные рефакторинги

Перемещение поля

Помогает рефакторингу

Извлечение класса

Встраивание класса

Борется с запахом

Стрельба дробью

Параллельные иерархии наследования

Неуместная близость

акже известен как:Remove Middle Man

Рефакторинг Удаление посредника

Проблема

Класс имеет слишком много методов, которые просто делегируют работу другим объектам.

Решение

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

Приёмы рефакторинга. Перемещение методов между классами

Приёмы рефакторинга. Перемещение методов между классами

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

В этом рефакторинге мы будем использовать названия из сокрытия делегирования, а именно:

  • Сервер — это объект, к которому клиент имеет непосредственный доступ.

  • Делегат — это конечный объект, который содержит функциональность, нужную клиенту.

Существует два вида проблем:

  1. Класс-сервер ничего не делает сам по себе, создавая бесполезную сложность. В этом случае стоит задуматься, нужен ли этот класс вообще.

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

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

  1. Создайте геттер для доступа к объекту класса-делегата из объекта класса-сервера.

  2. Замените вызовы делегирующих методов класса-сервера прямыми вызовами методов класса-делегата.

Анти-рефакторинг

Сокрытие делегирования

Борется с запахом

Посредник

Также известен как: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 {
  //...
  public function sendReport() {
    $previousDate = clone $this->previousDate;
    $paymentDate = $previousDate->modify("+7 days");
    //...
  }
}
class Report {
  //...
  public function sendReport() {
    $paymentDate = self::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)
class Report {
  //...
  sendReport(): void {
    let nextDay: Date = new Date(previousEnd.getYear(),
      previousEnd.getMonth(), previousEnd.getDate() + 1);
    //...
  }
}
class Report {
  //...
  sendReport() {
    let newStart: Date = nextDay(previousEnd);
    //...
  }
  private static nextDay(arg: Date): Date {
    return new Date(arg.getFullYear(), arg.getMonth(), arg.getDate() + 1);
  }
}

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

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

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

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

Достоинства

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

Недостатки

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

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

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

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

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

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

Родственные рефакторинги

Введение локального расширения

Вынести все расширенные методы в отдельный класс обертку/наследник служебного класса.

Борется с запахом

Неполнота библиотечного класса

Также известен как:Introduce Local Extension

Рефакторинг Введение локального расширения

Проблема

В служебном классе отсутствуют некоторые методы, которые вам нужны. При этом добавить их в этот класс вы не можете.

Решение

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

Приёмы рефакторинга. Перемещение методов между классами
Приёмы рефакторинга. Перемещение методов между классами

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

В классе, который вы используете, нет нужных вам методов. Или еще хуже — вы не можете их туда добавить (например, потому что классы находятся в сторонней библиотеке). У вас есть два пути:

  • Создать подкласс из интересующего класса, который будет содержать новые методы, и наследовать все остальное из родительского класса. Этот путь проще, но иногда бывает заблокирован в самом служебном классе с помощью директивы final.

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

Достоинства

  • Помещая дополнительные методы в отдельный класс-расширение (обертку или подкласс), вы не засоряете клиентские классы кодом, который им не принадлежит по смыслу. Этим повышается связность компонентов программы и возможность их повторного использования.

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

  1. Создайте новый класс-расширение:

    • либо сделайте его наследником служебного класса;

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

  2. Создайте конструктор, использующий параметры конструктора служебного класса.

  3. Кроме того, создайте альтернативный «конвертирующий» конструктор, который принимает в параметрах только объект оригинального класса. Это поможет в подстановке расширения вместо объектов оригинального класса.

  4. Создайте в классе новые расширенные методы. Переместите в него внешние методы из других классов, либо удалите их, если расширение уже имеет такой функционал.

  5. Замените использование служебного класса новым классом-расширением в тех местах, где нужна расширенная функциональность.

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

создано: 2019-01-25
обновлено: 2024-11-13
3



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей

Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Теория рефакторинга

Термины: Теория рефакторинга