Архитектура / паттерны · 4 / 4

Strategy, Decorator, Adapter и Command

Узнаём задачу паттерна и ловушки делегирования

Выберите изменяемую часть

Strategy заменяет алгоритм под общим договором. Decorator оборачивает тот же договор дополнительным поведением. Adapter переводит чужой интерфейс в нужный приложению, а Facade даёт удобный вход в несколько операций подсистемы. Command представляет действие данными/объектом; возможность undo требует отдельного обратного действия или снимка.

Это классификация для разбора исходных примеров из draft/patterns.md: сама форма «класс содержит другой класс» не определяет паттерн. Проверяйте, что именно меняется и какой договор видит клиент.

Названия взяты из каталога Gamma, Helm, Johnson и Vlissides — Design Patterns. Издатель также предоставляет авторский фрагмент об Adapter: его назначение — согласование интерфейсов. Примеры на Kotlin ниже составлены для этой темы.

Маленькая стратегия

fun interface Shipping { fun cost(weight: Int): Int }
class Checkout(private val shipping: Shipping) {
    fun delivery(weight: Int): Int = shipping.cost(weight)
}
val freeDelivery = Checkout(Shipping { 0 })

Для одного метода Kotlin fun interface допускает SAM-преобразование из лямбды. Множество наследников не обязательно. Функциональные интерфейсы Kotlin.

by не меняет внутренние вызовы делегата

interface Reporter {
    fun message(): String
    fun report(): String
}
class PlainReporter : Reporter {
    override fun message() = "plain"
    override fun report() = message()
}
class Loud(private val base: Reporter) : Reporter by base {
    override fun message() = "LOUD"
}

Loud(PlainReporter()).report() вернёт plain: делегированный report выполняется на base, его вызов message не перенаправляется в обёртку. Если нужна другая семантика, явно переопределите report. Делегирование Kotlin.

Порядок обёрток — часть поведения

В нашем примере Logging(Retry(client)) пишет один лог на всю операцию, а Retry(Logging(client)) — лог каждой попытки, если Logging логирует каждый вызов. Для кеша и авторизации порядок тоже требует договорённости. Паттерн не освобождает от проверки ошибок и побочных эффектов.

DI позволяет передать выбранную комбинацию снаружи и подменить её в тесте. Dependency injection.

Основа отбора: draft/patterns.md, draft/Architecture interview.md, вопросы ООП из draft/LINKS.txt.

К вопросам →