Шаблонный метод — шаблоны проектирования в деталях

Шаблонный метод — это популярный поведенческий шаблон проектирования. При его помощи можно задать некоторое поведение в методе абстрактного класса, но при этом оставить детали реализации на классы-наследники. Проще говоря, в контексте языка программирования Java шаблонный метод — это метод абстрактного класса или метод по умолчанию интерфейса, задающий общее поведение, но опирающийся на другие абстрактные методы. Шаблонный метод наряду с шаблоном проектирования «Стратегия» часто применяется при реализации инверсии управления.

Демонстрируя пример реализации шаблона проектирования «Декоратор», я использовал и шаблонный метод в классе CachingFindTaskByIdDecorator:

Метод findTaskById в данном случае реализует шаблон проектирования «Шаблонный метод», он задаёт некоторое поведение, но оставляет детали реализации, поиск и сохранение задачи в кэше, на классы-наследники.

Тестирование шаблонного метода

Как правило, тестирование шаблонного метода происходит при тестировании классов-наследников. Однако возможна ситуация, когда классов-наследников у абстрактного класса, содержащего шаблонный метод, нет наследников в рамках проекта. Происходит это в случаях, когда вы разрабатываете какой-то фреймворк или библиотеку и хотите, чтобы реализацию этого абстрактного класса предоставлял пользователь вашей библиотеки. В этом случае всё же желательно написать тест для абстрактного класса, содержащего шаблонный метод. Сделать это можно двумя способами: при помощи тестовой реализации абстрактного класса или при помощи фреймворков для создания объектов-имитаций, например Mockito.

В первом случае вам необходимо создать в директории тестовых классов максимально простой класс, реализующий тестируемый абстрактный класс. Для CachingFindTaskByIdDecorator тестовая реализация может выглядеть следующим образом:

Теперь необходимо написать тест для TestingCachingFindTaskByIdDecorator:

Я не сторонник создания классов специально для тестов вроде TestingCachingFindTaskByIdDecorator, поэтому предлагаю рассмотреть второй вариант. В нём необходимо будет создать объект-имитацию CachingFindTaskByIdDecorator, но использовать реальный метод findTaskById. Кроме этого при создании объекта-имитации потребуется использовать правильный конструктор для передачи декорируемого объекта.

Тест будет выглядеть следующим образом:

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

Применяйте шаблонный метод для реализации общего поведения в абстрактных классах для придания большей гибкости вашему коду.

Статья в паблике VK