Autumn SALE

Замена кодирования типа состоянием/стратегией

Также известен как: Replace Type Code with State/Strategy

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

Проблема

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

Решение

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

До
Replace Type Code with State-Strategy - Before
После
Replace Type Code with State-Strategy - After

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

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

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

Достоинства

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

  • Если вам потребуется добавить новое значение закодированного типа, все что придётся сделать — это добавить новый подкласс-состояние, не трогая существующий код (принцип открытости/закрытости).

Недостатки

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

Полезные факты

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

Вам подойдёт Стратегия, если вы пытаетесь разделить условный оператор, управляющий выбором того или иного алгоритма.

Однако если каждое значение закодированного типа отвечает не просто за альтернативную версию алгоритма, а за целое состояние класса, значение полей и множество других действий, вам больше подойдёт Состояние.

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

  1. Используйте самоинкапсуляцию поля для создания геттера для поля, которое содержит кодирование типа.

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

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

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

  5. В исходном классе, поменяйте тип закодированного поля на класс-состояние. В сеттере этого поля, вызывайте фабричный метод состояния для получения новых объектов состояний.

  6. Теперь можете начинать перемещать поля и методы из суперкласса в соответствующие подклассы-состояния (при помощи спуска поля и спуска метода).

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