Книга: Экстремальное программирование. Разработка через тестирование
Встраиваемый объект (Pluggable Object)
Встраиваемый объект (Pluggable Object)
Как можно выразить несколько разных вариантов поведения кода? Проще всего использовать явный условный оператор:
if(circle) then {
… код, относящийся к circle.
} else {
… код, не относящийся к circle
}
Однако подобный корявый код имеет тенденцию распространяться по всей программе. Если для определения разницы между окружностями и не окружностями вы будете использовать условный оператор хотя бы в одном месте вашего кода, с большой долей уверенности можно сказать, что позднее подобный оператор придется добавить также в другом месте, затем в третьем и т. д.
Вторая по важности задача TDD – устранение дублирования, поэтому вы должны подавить угрозу распространения явных условных операторов в зародыше. Если вы видите, что одно и то же условие проверяется в двух разных местах вашего кода, значит, настало время выполнить базовое объектно-ориентированное преобразование: «Встраиваемый объект» (PluggableObject).
Иногда обнаружить необходимость применения этого шаблона не так просто. Один из самых любимых мною примеров использования встраиваемого объекта был придуман мною и Эрихом Гаммой. Представьте, что мы занимаемся разработкой графического редактора. Если вы когда-нибудь занимались чем-либо подобным, должно быть, вы знаете, что операция выделения объектов обладает несколько усложненной логикой. Если указатель мыши находится над графической фигурой и пользователь нажимает кнопку мыши, значит, последующие перемещения мыши приводят к перемещению фигуры, а при отпускании кнопки мыши выбранная фигура остается на новом месте. Если указатель мыши не находится над какой-либо фигурой, значит, нажав кнопку, пользователь выделяет несколько фигур, последующие перемещения мыши приводят к изменению размера прямоугольника выделения, а при отпускании кнопки мыши фигуры внутри прямоугольника выделения становятся выделенными. Изначальный код выглядит примерно так:
SelectionTool
Figure selected;
public void mouseDown() {
selected = findFigure();
if (selected!= null)
select(selected);
}
public void mouseMove() {
if (selected!= null)
move(selected);
else
moveSelectionRectangle();
}
public void mouseUp() {
if (selected == null)
selectAll();
}
В глаза бросаются три похожих условных оператора (я же говорил, что они плодятся, как мухи). Что делать, чтобы избавиться от них? Создаем встраиваемый объект, SelectionMode, обладающий двумя реализациями: SingleSelection и MultipleSelection.
SelectionTool
SelectionMode mode;
public void mouseDown() {
selected = findFigure();
if (selected!= null)
mode = SingleSelection(selected);
else
mode = MultipleSelection();
}
public void mouseMove() {
mode.mouseMove();
}
public void mouseUp() {
mode.mouseUp();
}
В языках с явными интерфейсами вы обязаны реализовать интерфейс с двумя (или больше) встраиваемыми объектами.
- Команда (Command)
- Объект-значение (Value Object)
- Нуль-объект (Null Object)
- Шаблонный метод (Template Method)
- Встраиваемый объект (Pluggable Object)
- Встраиваемый переключатель (Pluggable Selector)[26]
- Фабричный метод (Factory Method)
- Самозванец (Imposter)
- Компоновщик (Composite)
- Накапливающий параметр (Collecting Parameter)
- Одиночка (Singleton)
- 1.1. Введение в объектно-ориентированное программирование
- ЧАСТЬ IV. База данных и ее объекты.
- 1.1.1. Что такое объект
- Практическая работа 53. Запуск Access. Работа с объектами базы данных
- Физические объекты
- Иерархия объектов в InterBase
- Встраиваемый сервер
- Имена объектов длиной 68 символов
- Создание объектов Collection
- 7.12. Объективизация времени
- 3.3. Определение объектов защиты
- 5.2.3. Действия с объектами Numbers