Мартин Фаулер. Рефакторинг
Дублирование кода
Длинный метод
Если ощущается необходимость что-то прокомментировать, надо писать метод.
Комментарии указывают на семантическое расстояние.
Большой класс
Длинный список параметров
Расходящиеся модификации
Один класс часто модифицируется различными способами по разным причинам
«Стрельба дробью»
Противоположность расходящейся модификации – внесение множества мелких
изменений в большое число классов.
Завистливые функции
Метод, который больше интересуется не тем классом, в котором он находится, а
каким-то другим.
Группы данных
Группировку данных вынести в отдельный класс
Одержимость элементарными типами
Использовать маленькие объекты для маленьких задач
Операторы switch
Плохая инкапсуляция и отсутствие полиморфизма
Параллельные иерархии наследования
При порождении подкласса одного из классов приходится создавать подкласс
другого класса
Ленивый класс
Класс, существование которого не окупается выполняемыми им функциями
Теоретическая общность
Задел на будущее
Временное поле
В некотором объекте атрибут устанавливается толкьо при определенных
обстоятельствах
Цепочки сообщений
Делегация параметров через несколько классов
Посредник
Класс делегирует обработку другому классу
Неуместная близость
Слишком тесная связь двух классов
Альтернативные классы с разными интерфейсами
Дублирование функций в двух классах
Неполнота библиотечного класса
Классы данных
Содержат только поля и способы доступа к этим полям
Отказ от наследства
Наследнику не требуются методы и свойства родительского класса
Комментарии
Наличие комментариев свидетельствует о непонятности кода
Выделение меотда (Extract Method)
Преобразуйте фрагмент кода в метод, название которого объясняет его значение.
Встраивание метода (Inline Method)
Тело метода столь же понятно, как и его название
Встраивание временной
переменной (Inline Temp)
Замена временной
переменной вызовом метода (Replace Temp with Query)
Преобразуйте выражение в метод. Новый метод может быть использован в других местах.
Введение проясняющей
переменной (Introduce Explaining Variable)
Поместите результат выражения или его части во временную переменную, имя
которой поясняет его назначение
Расщепление временной
переменной (Split Temporary Variable)
Имеется переменная, которой неоднократно присваивается значение, имеющее
различный смысл.
Удаление присваиваний параметрам (Remove Assignments to Parameters)
Избегайте присваиваний параметрам. Попробуйте сделать так,
чтобы метод возвращал одно значение. Если необходимо возвратить несколько
значений, попытайтесь преобразовать группу данных в объект.
Замена метода объектом методов (Replace Method with Method Object)
Преобразуйте длинный метод в отдельный объект так, чтобы
локальные переменные стали полями этого объекта.
Замещение алгоритма (Substitute Algorithm)
Замените тело метода новым, более понятным алгоритмом.
Перемещение метода (Move Method)
Метод чаще использует функции другого класса (или используется ими), а не того,
в котором он определен.
Перемещение поля (Move Field)
Выделение класса (Extract Class)
Некоторый класс выполняет работу, которую следует поделить между двумя классами
Встраивание класса (Inline Class)
Класс выполняет слишком мало функций. Переместите все функции в другой класс и
удалите исходный.
Сокрытие делегирования (Hide Delegate)
Клиент обращается к делегируемому классу объекта. Создайте на сервере методы,
скрывающие делегирование.
Удаление посредника (Remove Middle Man)
Класс слишком занят простым делегированием. Заставьте клиента обращаться к
делегату непосредственно.
Введение внешнего метода (Introduce Foreign Method)
Необходимо ввести в сервер дополнительный метод, но
отсутствует возможность модификации класса. Создайте в классе клиента метод,
которому в качестве первого аргумента передается класс сервера.
Введение локального
расширения (Introduce Local Extension)
Используемый класс сервера требуется дополнить несколькими методами, но класс
недоступен для модификации. Создайте новый класс с необходимыми
дополнительными методами. Сделайте его подклассом или оболочкой для исходного
класса.
Самоинкапсуляция поля (Self Encapsulate Field)
Создайте методы получения и установки значения поля и обращайтесь к полю только
через них.
Замена значения данных
объектом (Replace Data Value with Object)
Есть некоторый элемент данных, для которого требуются дополнительные данные или
поведение. Преобразуйте элемент данных в объект.
Замена значения ссылкой
(Change Value to Reference)
Есть много одинаковых экземпляров одного класса, которые требуется заменить
одним объектом. Превратите объект в объект ссылки. (Order -> Customer. Customer лучше иметь в виде ссылки)
Замена ссылки значением (Change Reference to Value)
Имеется маленький, неизменяемый и неудобный в управлении
объект ссылки. Превратите его в объект значения. (Company - > Currency)
Замена массива объектом
(Replace Array with Object)
Есть массив, некоторые элементы которого могут означать разные сущности.
Замените массив объектом, в котором есть поле для каждого элемента.
Дублирование видимых
данных (Duplicate Observed Data)
Есть данные предметной области, присутствующие только в графическом элементе GUI. К этим данным нужен доступ методам предметной области.
Скопируйте данные в объект предметной области. Создайте объект-наблюдатель,
который будет обеспечивать синхронность данных.
Замена однонаправленной
связи двунаправленной (Change Unidirectional Association to Bidirectional)
Есть два класса, каждый из которых должен использовать функции другого, но
ссылка между ними есть только в одном направлении. Добавьте обратные указатели
и измените модификаторы.
Замена двунаправленной
связи однонаправленной (Change Bidirectional Association to Unidirectional)
Имеется двунаправленная связь, но одному из классов больше не нужны функции
другого класса. Опустить ненужный конец связи.
Замена магического числа
символической константой (Replace Magic Number with Symbolic Constant)
Инкапсуляция поля (Encapsulate Field)
Имеется открытое поле. Сделайте его закрытым и обеспечьте методы доступа.
Инкапсуляция колекции (Encapsulate Collection)
Метод возвращает коллекцию. Сделайте возвращаемое методом значение доступным
только для чтения и создайте методы добавления/удаления элементов.
Замена записи классом
данных (Replace Record with Data Class)
Требуется взаимодействие со структурой записи в традиционной программной среде.
Создайте для записи немой объект данных.
Замена кода типа классом
(Replace Type Code with Class)
У класса есть числовой тип, который не влияет на его поведение. Замените число
новым классом. (Person -> BloodGroup)
Замена кода типа
подклассами (Replace Type Code with Subclasses)
Имеется неизменный код типа, воздействующий на поведение класса. Замените код
типа подклассами. (Employee <- Engineer + Employee <- Salesman)
Замена кода типа
состоянием/стратегией (Replace Type Code with State/Strategy)
Есть код типа, влияющий на поведение класса, но нельзя применить создание подклассов. Замените код типа объектом состояния. (Employee - EmployeeType, EmployeeType <-Engineer + EmployeeType <-Salesman)
Замена подкласса полями (Replace Subclass with Fields)
Есть подклассы, которые различаются только методами,
возвращающими данные-константы. Замените методы полями в родительском классе и
удалите классы.
Декомпозиция условного
оператора (Decompose Conditional)
Имеется сложная условная цепочка проверок (if-then-else). Выделите методы из условия, части “then” и частей “else”.
Консолидация условного
выражения (Consolidate Conditional Expression)
Есть ряд проверок условия, дающих одинаковый результат.
Объедините их в одно условное выражение и выделите его.
Консолидация
дублирующихся условных фрагментов (Consolidate Duplicate Conditional Fragments)
Один и тот же фрагмент кода присутствует во всех ветвях условного выражения.
Переместите его за пределы выражения.
Удаление управляющего
флага (Remove Control Flag)
Имеется переменная, действующая как управляющий флаг для ряда булевых выражений.
Используйте вместо нее break или return.
Замена вложенных
условных операторов граничным оператором (Replace Nested Conditional with Guard Clauses)
Метод использует условное поведение, из которго неясен нормальный
путь выполнения. Используйте граничные условия для всех особых случаев. Для
каждой проверки вставьте граничный оператор. Граничный оператор осуществляет
возврат или возбуждает исключение.
Замена условного
оператора полиморфизмом (Replace Conditional with Polymorphism)
Есть условный оператор, поведение которого зависит от типа объекта. Переместите
каждую ветвь условного оператора в перегруженный метод подкласса. Сделайте
исходный метод абстрактным.
Введение объекта Null (Introduce Null Object)
Есть многократные проверки совпадения значения с null. Замените значение null объектом null.
Введение утверждения (Introduce Assertion)
Некоторая часть кода предполагает определенное состояние программы. Сделайте
предположение явным с помощью операторов утверждения.
Переименование метода (Rename Method)
Добавление параметра (Add Parameter)
Удаление параметра (Remove Parameter)
Разделение запроса и
модификатора (Separate Query from Modifier)
Есть метод, возвращающий значение, но, кроме того, изменяющий состояние
объекта. Создайте два метода – один для запроса и один для модификации.
Параметризация метода (Parameterize Method)
Несколько методов выполняют сходные действия, но с различными значениями,
содержащимся в теле метода. Создайте один метод, который использует для задания
разных значений параметр.
Замена параметра явными методами (Replace Parameter with Explicit Methods)
Есть метод, выполняющий разный код в зависимости от
значения параметра перечисляемого типа. Создайте отдельный метод для каждого
значения параметра.
Сохранение всего объекта
(Preserve Whole Object)
Вы получаете от объекта несколько значений, которые затем передаете как
параметры при вызове метода. Передавайте вместо этого весь объект.
Замена параметра вызовом
метода (Replace Parameter with Method)
Объект вызывает метод, а затем передает полученный результат в качестве параметра
метода. Получатель значения тоже может вызвать этот метод. Уберите параметр и
заставьте получателя вызвать этот метод.
Введение граничного
объекта (Introduce Parameter Object)
Есть группа параметров, естественным образом связанных друг с другом. Замените
их объектом.
Удаление метода
установки значения (Remove Setting Method)
Поле должно быть установлено в момент создания и больше никогда не изменяться.
Удалите методы, устанавливающие значение этого поля.
Сокрытие метода (Hide Method)
Метод не используется никаким другим классом. Сделайте метод закрытым.
Замена конструктора
фабричным методом (Replace Factory with Factory Method)
Инкапсуляция нисходящего
преобразования (Encapsulate Downcast)
Метод возвращает объект, к которому вызывающий должен применить нисходящее
преобразование типа. Переместите нисходящее преобразование внутрь метода.
Замена кода ошибки
исключительной ситуацией (Replace Error Code with Exception)
Замена исключительной
ситуации проверкой (Replace Exception with Test)
Возбуждается исключение при выполнении условия, которое вызывающий мог сначала
проверить. Измените код вызова так, чтобы он сначала выполнял проверку.
Подьем поля (Pull Up Field)
В двух подклассах есть одинаковое поле. Переместите поле
в родительский класс.
Подъем метода (Pull Up Method)
В подклассах есть методы с идентичными результатами.
Переместите их в родительский класс.
Подъем тела конструктора
(Pull Up Constructor Body)
Имеются конструкторы подклассов с почти идентичными телами. Создайте
конструктор в родительском классе; вызывайте его из методов подклассов.
Спуск метода (Push Down Method)
В родительском классе есть поведение, относящееся только
к некоторым из его подклассов. Переместить поведение в эти подклассы.
Спуск поля (Push Down Field)
Есть поле, используемое лишь некоторыми подклассами. Переместите поле в эти
подклассы.
Выделение подкласса (Extract Subclass)
В классе есть функции, используемые только в некоторых
случаях. Создайте подкласс для этого подмножества функций.
Выделение родительского
класса (Extract Superclass)
Имеются два класса со сходными функциями. Создайте для них общий родительский
класс и переместите в него общие функции.
Выделение интерфейса (Extract Interface)
Несколько клиентов пользуются одним и тем же подмножеством интерфейса класса
или в двух классах часть интерфейса является общей. Выделите это подмножество в
интерфейс.
Свертывание иерархии (Collapse Hierarchy)
Родительский класс и подкласс мало отличаются. Объедините их в один.
Формирование шаблона
метода (Form Template Method)
Есть два метода в подклассах, выполняющие аналогичные шаги в одинаковом
порядке, однако эти шаги различны. Образуйте из этих шагов методы с одинаковой
сигнатурой, чтобы исходные методы стали одинаковыми. После этого можно их
поднять в родительский класс.
Замена наследования
делегированием (Replace Inheritance with Delegation)
Подкласс использует только часть интерфейса родительского класса или не желает
наследовать данные. Создайте поле для родительского класса, настройте методы,
чтобы они делегировали выполнение родительскому классу, и удалите подклассы.
Замена делегирования
наследованием (Replace Delegation with Inheritance)
Вы используете делегирование и часто пишите много
простых делегирований для интерфейса в целом. Сделайте делегирующий класс
подклассом делегата.
Разделение наследования
(Tease Apart Inheritance)
Есть иерархия наследования, которая выполняет
одновременно две задачи. Создайте две иерархии и используйте делегирование для
вызова одной из другой.
Преобразование
процедурного проекта в объекты (Convert Procedural Design to Objects )
Имеется код, написанный в процедурном стиле.
Преобразуйте записи данных в объекты, разделите поведение и переместите
поведение в объекты.
Отделение предметной
области от представления (Separate Domain from Presentation)
Имеются классы GUI, содержащие логику предметной области. Выделите логику
предметной области в отдельные классы предментой области.
Выделение иерархии (Extract Hierarchy)
Есть класс, выполняющий слишком много работы, частично
или полностью через многочисленные условные операторы. Создайте иерархию
классов, в которой каждый подкласс представляет конкретный случай.