65 lines
4.2 KiB
Markdown
65 lines
4.2 KiB
Markdown
#рефакторинг #методы_рефакторинга
|
||
|
||
![[Pasted image 20250220082420.png]]
|
||
|
||
### **Проблема**
|
||
У вас есть подкласс, который использует только часть методов суперкласса или не хочет наследовать его данные.
|
||
```javascript
|
||
class Order {
|
||
get daysToShip() {
|
||
return this._warehouse.daysToShip;
|
||
}
|
||
}
|
||
|
||
class PriorityOrder extends Order {
|
||
get daysToShip() {
|
||
return this._priorityPlan.daysToShip;
|
||
}
|
||
}
|
||
```
|
||
|
||
### **Решение**
|
||
Создайте поле и поместите в него объект суперкласса, делегируйте выполнение методов объекту-суперклассу, уберите наследование.
|
||
```javascript
|
||
class Order {
|
||
get daysToShip() {
|
||
return (this._priorityDelegate)
|
||
? this._priorityDelegate.daysToShip
|
||
: this._warehouse.daysToShip;
|
||
}
|
||
}
|
||
|
||
class PriorityOrderDelegate {
|
||
get daysToShip() {
|
||
return this._priorityPlan.daysToShip
|
||
}
|
||
}
|
||
```
|
||
|
||
### **Причины рефакторинга**
|
||
Замена наследования композицией может значительно улучшить дизайн классов, если:
|
||
- Ваш подкласс нарушает [[Принцип подстановки Лисков| принцип замещения Барбары Лисков]]. Другими словами, наследование возникло только ради объединения общего кода, но не потому, что подкласс «является» (is-a) расширением суперкласса.
|
||
- Подкласс использует только часть методов суперкласса. В этом случае, это только вопрос времени, пока кто-то не вызовет метод суперкласса, который он не должен был вызывать.
|
||
|
||
Суть рефакторинга сводится к тому, чтобы разделить оба класса, и сделать суперкласс помощником подкласса, а не его родителем. Вместо того чтобы наследовать все методы суперкласса, подкласс будет иметь только необходимые методы, которые будут делегировать выполнение методам объекта-суперкласса.
|
||
|
||
### **Достоинства**
|
||
|
||
- Класс не содержит лишних методов, которые достались ему в наследство от суперкласса.
|
||
- В поле-делегат можно подставлять разные объекты, имеющие различные реализации функциональности. По сути, вы получаете реализацию паттерна проектирования [[Стратегия]].
|
||
|
||
### **Недостатки**
|
||
|
||
### **Порядок рефакторинга**
|
||
1. Создайте поле в подклассе для содержания суперкласса. На первом этапе поместите в него текущий объект.
|
||
2. Измените методы подкласса так, чтобы они использовали объект суперкласса, вместо this.
|
||
3. Для методов, которые были унаследованы из суперкласса и которые вызываются в клиентском коде, в подклассе нужно создать простые делегирующие методы.
|
||
4. Уберите объявление наследования из подкласса
|
||
5. Измените код инициализации поля, в котором хранится бывший суперкласс, созданием нового объекта
|
||
|
||
### **Обратный рефакторинг**
|
||
- [[Замена суперкласса делегатом (Replace Superclass with Delegate)]]
|
||
|
||
### **Ссылки**
|
||
- https://refactoring.guru/ru/replace-inheritance-with-delegation
|
||
- [[Мартин Фаулер - Рефакторинг кода на JavaScript]] |