Refactoring.
A controlled technique for improving the design of existing code. Browse by group, see the code smells these techniques treat, the test smells in your test suite, or the smells of AI-generated code.
Проблема: Методу не хватает данных для осуществления каких-то действий. Решение: Создайте новый параметр, чтобы передать эти данные.
Проблема: Метод не используется другими классами либо используется только внутри своей иерархии классов. Решение: Сделайте метод приватным или защищённым.
Проблема: В ваших методах встречается повторяющаяся группа параметров. Решение: Замените эти параметры объектом.
Проблема: Несколько методов выполняют похожие действия, которые отличаются только какими-то внутренними значениями, числами или операциями. Решение: Объедините все эти методы в один с параметром, в который будет передаваться отличающееся значение.
Проблема: Вы получаете несколько значений из объекта, а затем передаёте их в метод как параметры. Решение: Вместо этого передавайте весь объект.
Проблема: Параметр не используется в теле метода. Решение: Удалите неиспользуемый параметр.
Проблема: Значение поля должно быть установлено только в момент создания и больше никогда не меняться. Решение: Удалите методы, устанавливающие значение этого поля.
Проблема: Название метода не раскрывает суть того, что он делает. Решение: Измените название метода.
Проблема: У вас есть сложный конструктор, делающий нечто большее, чем простая установка значений полей объекта. Решение: Создайте фабричный метод и замените им вызовы конструктора.
Проблема: Метод возвращает определенное значение, которое будет сигнализировать об ошибке. Решение: Вместо этого следует выбрасывать исключение.
Проблема: Вы выбрасываете исключение там, где можно было бы обойтись простой проверкой условия. Решение: Замените выбрасывание исключения проверкой этого условия.
Проблема: Метод разбит на части, каждая из которых выполняется в зависимости от значения какого-то параметра. Решение: Извлеките отдельные части метода в собственные методы и вызывайте их вместо оригинального метода.
Проблема: Вызываем метод и передаем его результаты как параметры другого метода. При этом значение параметров могли бы быть получены и внутри вызываемого метода. Решение: Вместо передачи значения через параметры метода, попробуйте переместить код получения значения внутрь самого метода.
Проблема: У вас есть метод, который возвращает какое-то значение, но при этом в процессе работы он изменяет что-то внутри объекта. Решение: Разделите метод на два разных метода. Один из них пускай возвращает значение, а второй модифицирует объект.
Проблема: У вас есть двухсторонняя связь между классами, но один из классов больше не использует фичи другого. Решение: Уберите неиспользуемую связь.
Проблема: У вас есть объект-ссылка, который слишком маленький и неизменяемый, чтобы оправдать сложности по управлению его жизненным циклом. Решение: Превратите его в объект-значение.
Проблема: У вас есть два класса, которым нужно использовать фичи друг друга, но между ними существует только односторонняя связь. Решение: Добавьте недостающую связь в класс, в котором она отсутствует.
Проблема: Есть много одинаковых экземпляров одного класса, которые можно заменить одним объектом. Решение: Превратите одинаковые объекты в один объект-ссылку.
Проблема: Данные предметной области программы хранятся в классах, отвечающих за пользовательский интерфейс (GUI). Решение: Имеет смысл выделить данные предметной области в отдельные классы и, таким образом, обеспечить связь и синхронизацию между классом предметной области и GUI.
Проблема: Класс содержит поле-коллекцию и простой геттер и сеттер для работы с этой коллекцией. Решение: Сделайте возвращаемое геттером значение доступным только для чтения и создайте методы добавления/удаления элементов этой коллекции.
Проблема: У вас есть публичное поле. Решение: Сделайте поле приватным и создайте для него методы доступа.
Проблема: У вас есть массив, в котором хранятся разнотипные данные. Решение: Замените массив объектом, который будет иметь отдельные поля для каждого элемента.
Проблема: В классе (или группе классов) есть поле простого типа. У этого поля есть своё поведение и связанные данные. Решение: Создайте новый класс, поместите в него старое поле и его поведения, храните объект этого класса в исходном классе.
Проблема: В коде используется число, которое несёт какой-то определённый смысл. Решение: Замените это число константой с человеко-читаемым названием, объясняющим смысл этого числа.
Проблема: У вас есть подклассы, которые отличаются только методами, возвращающими данные-константы. Решение: Замените методы полями в родительском классе и удалите подклассы.
Проблема: В классе есть поле, содержащее кодирование типа. Значения этого типа не используются в условных операторах и не влияют на поведение программы. Решение: Создайте новый класс и применяйте его объекты вместо значений закодированного типа.
Проблема: У вас есть закодированный тип, который влияет на поведение, но вы не можете использовать подклассы, чтобы избавиться от него. Решение: Замените кодирование типа объектом-состоянием. При необходимости заменить значение поля с кодированием типа, в него подставляется другой объект-состояние.
Проблема: У вас есть закодированный тип, который непосредственно влияет на поведение программы (основываясь на значениях этого поля, в условных операторах выполняется различный код). Решение: Для каждого значения закодированного типа, создайте подклассы. А затем, вынесите соответствующие поведения из исходного класса в эти подклассы. Управляющий код замените полиморфизмом.
Проблема: Вы используете прямой доступ к приватным полями внутри класса. Решение: Создайте геттер и сеттер для поля, и пользуйтесь для доступа к полю только ими.
Проблема: У вас есть некая иерархия классов, в которой подкласс мало чем отличается от суперкласса. Решение: Слейте подкласс и суперкласс воедино.
Проблема: Несколько клиентов пользуются одной и той же частью интерфейса класса. Либо в двух классах часть интерфейса оказалась общей. Решение: Выделите эту общую часть в свой собственный интерфейс.
Проблема: Класс имеет фичи, которые используются только в определённых случаях. Решение: Создайте подкласс и используйте его в этих случаях.
Проблема: У вас есть два класса с общими полями и методами. Решение: Создайте для них общий суперкласс и перенесите туда одинаковые поля и методы.
Проблема: В подклассах реализованы алгоритмы, содержащие похожие шаги и одинаковый порядок выполнения этих шагов. Решение: Вынесите структуру алгоритма и одинаковые шаги в суперкласс, а в подклассах оставьте реализацию отличающихся шагов.
Проблема: Подклассы имеют конструкторы с преимущественно одинаковым кодом. Решение: Создайте конструктор в суперклассе и вынесите в него общий для подклассов код. Вызывайте конструктор суперкласса в конструкторах подкласса.
Проблема: Два класса имеют одно и то же поле. Решение: Переместите поле в суперкласс, убрав его из подклассов.
Проблема: Подклассы имеют методы, которые делают схожую работу. Решение: В этом случае нужно сделать методы идентичными, а затем переместить их в суперкласс.
Проблема: Поле используется только в некоторых подклассах. Решение: Переместите поле в эти подклассы.
Проблема: Поведение, реализованное в суперклассе, используется только одним или несколькими подклассами. Решение: Переместите это поведение в подклассы.
Проблема: Класс содержит множество простых делегирующих методов ко всем методам другого класса. Решение: Сделайте класс наследником делегата, после чего делегирующие методы потеряют смысл.
Проблема: У вас есть подкласс, который использует только часть методов суперкласса или не хочет наследовать его данные. Решение: Создайте поле и поместите в него объект суперкласса, делегируйте выполнение методов объекту-суперклассу, уберите наследование.
Проблема: У вас есть несколько условных операторов, ведущих к одинаковому результату или действию. Решение: Объедините все условия в одном условном операторе.
Проблема: Одинаковый фрагмент кода находится во всех ветках условного оператора. Решение: Вынесите его за рамки оператора.
Проблема: У вас есть сложный условный оператор (if-then/else или switch). Решение: Выделите в отдельные методы все сложные части оператора: условие, then и else.
Проблема: Корректная работа участка кода предполагает наличие каких-то определённых условий или значений. Решение: Замените эти предположения конкретными проверками.
Проблема: Из-за того, что некоторые методы возвращают null вместо реальных объектов, у вас в коде присутствует множество проверок на null. Решение: Вместо null возвращайте Null-объект, который предоставляет поведение по умолчанию.
Проблема: У вас есть булевская переменная, которая играет роль управляющего флага для нескольких булевских выражений. Решение: Используйте break, continue и return вместо этой переменной.
Проблема: У вас есть условный оператор, который, в зависимости от типа или свойств объекта, выполняет различные действия. Решение: Создайте подклассы, которым соответствуют ветки условного оператора. В них создайте общий метод и переместите в него код из соответствующей ветки условного оператора. Впоследствии замените условный оператор на вызов этого метода. Таким образом, нужная реализация будет выбираться через полиморфизм в зависимости от класса объекта.
Проблема: У вас есть группа вложенных условных операторов, среди которых сложно выделить нормальный ход выполнения кода. Решение: Выделите все проверки специальных или граничных случаев выполнения в отдельные условия и поместите их перед основными проверками. В идеале, вы должны получить «плоский» список условных операторов, идущих один за другим.
Проблема: Один класс работает за двоих. Решение: Создайте новый класс, переместите в него поля и методы, отвечающие за определённую функциональность.
Проблема: Клиент получает объект B из поля или метода объекта А. Затем клиент вызывает какой-то метод объекта B. Решение: Создайте новый метод в классе А, который бы делегировал вызов объекту B. Таким образом, клиент перестанет знать о классе В и зависеть от него.
Проблема: Класс почти ничего не делает, ни за что не отвечает, и никакой ответственности для этого класса не планируется. Решение: Переместите все фичи из описанного класса в другой.
Проблема: Служебный класс не содержит метода, который вам нужен, при этом у вас нет возможности добавить метод в этот класс. Решение: Добавьте метод в клиентский класс и передавайте в него объект служебного класса в качестве аргумента.
Проблема: В служебном классе отсутствуют некоторые методы, которые вам нужны. При этом добавить их в этот класс вы не можете. Решение: Создайте новый класс, который бы содержал эти методы, и сделайте его наследником служебного класса, либо его обёрткой.
Проблема: Поле используется в другом классе больше, чем в собственном. Решение: Создайте поле в новом классе и перенаправьте к нему всех пользователей старого поля.
Проблема: Метод используется в другом классе больше, чем в собственном. Решение: Создайте новый метод в классе, который использует его больше других, и перенесите туда код из старого метода. Код оригинального метода превратите в обращение к новому методу в другом классе либо уберите его вообще.
Проблема: Класс имеет слишком много методов, которые просто делегируют работу другим объектам. Решение: Удалите эти методы и заставьте клиента вызывать конечные методы напрямую.
Проблема: У вас есть фрагмент кода, который можно сгруппировать. Решение: Выделите участок кода в новый метод (или функцию) и вызовите этот метод вместо старого кода.
Проблема: У вас есть сложное для понимания выражение. Решение: Поместите результат выражения или его части в отдельные переменные, поясняющие суть выражения.
Проблема: Стоит использовать в том случае, когда тело метода очевиднее самого метода. Решение: Замените вызовы метода его содержимым и удалите сам метод.
Проблема: У вас есть временная переменная, которой присваивается результат простого выражения (и больше ничего). Решение: Замените обращения к переменной этим выражением.
Проблема: Параметру метода присваивается какое-то значение. Решение: Вместо параметра воспользуйтесь новой локальной переменной.
Проблема: У вас есть длинный метод, в котором локальные переменные так сильно переплетены, что это делает невозможным применение «извлечения метода». Решение: Преобразуйте метод в отдельный класс так, чтобы локальные переменные стали полями этого класса. После этого можно без труда разделить метод на части.
Проблема: Вы помещаете результат какого-то выражения в локальную переменную, чтобы использовать её далее в коде. Решение: Выделите все выражение в отдельный метод и возвращайте результат из него. Замените использование вашей переменной вызовом метода. Новый метод может быть использован и в других методах.
Проблема: У вас есть локальная переменная, которая используется для хранения разных промежуточных значений внутри метода (за исключением переменных циклов). Решение: Используйте разные переменные для разных значений. Каждая переменная должна отвечать только за одну определённую вещь.
Проблема: Вы хотите заменить существующий алгоритм другим? Решение: Замените тело метода, реализующего старый алгоритм, новым алгоритмом.