Практические шаблоны
Декораторы с делегированием
«Практические шаблоны» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Шаблон декоратора
Декоратор оборачивает объект, чтобы добавить поведение, сохраняя тот же интерфейс. Ключевое слово by в Kotlin делает декораторы очень простыми: переадресуйте все вызовы, а затем переопределите нужные части.
Базовый компонент
Начнём с простого источника данных. Декораторы будут оборачивать его.
interface DataSource {
fun fetch(): String
}
class NetworkSource : DataSource {
override fun fetch() = "raw-data"
}
fun main() {
println(NetworkSource().fetch())
}Декоратор журналирования
Декоратор делегирует работу обёрнутому источнику и добавляет журналирование вокруг интересующего его вызова.
interface DataSource { fun fetch(): String }
class NetworkSource : DataSource { override fun fetch() = "raw-data" }
class LoggingSource(private val inner: DataSource) : DataSource by inner {
override fun fetch(): String {
println("fetching...")
val result = inner.fetch()
println("done")
return result
}
}
fun main() {
println(LoggingSource(NetworkSource()).fetch())
}Декоратор кэширования
Другой декоратор кэширует первый результат, поэтому повторные вызовы пропускают базовый источник.
interface DataSource { fun fetch(): String }
class NetworkSource : DataSource { override fun fetch() = "raw-data" }
class CachingSource(private val inner: DataSource) : DataSource by inner {
private var cached: String? = null
override fun fetch(): String {
return cached ?: inner.fetch().also { cached = it }
}
}
fun main() {
val s = CachingSource(NetworkSource())
println(s.fetch())
println(s.fetch()) // served from cache
}Объединение декораторов
Поскольку каждый декоратор сам является DataSource, их можно объединять в цепочку. Порядок имеет значение: внешний декоратор оборачивает внутренний.
interface DataSource { fun fetch(): String }
class NetworkSource : DataSource { override fun fetch() = "raw-data" }
class LoggingSource(private val inner: DataSource) : DataSource by inner {
override fun fetch(): String { println("log"); return inner.fetch() }
}
class CachingSource(private val inner: DataSource) : DataSource by inner {
private var c: String? = null
override fun fetch() = c ?: inner.fetch().also { c = it }
}
fun main() {
val s = LoggingSource(CachingSource(NetworkSource()))
println(s.fetch())
println(s.fetch())
}Декоратор проверки
Декораторы также могут защищать входные данные. Здесь декоратор выполняет проверку перед делегированием настоящему исполнителю.
interface Processor { fun process(input: String): String }
class UpperProcessor : Processor { override fun process(input: String) = input.uppercase() }
class ValidatingProcessor(private val inner: Processor) : Processor by inner {
override fun process(input: String): String {
require(input.isNotBlank()) { "empty input" }
return inner.process(input)
}
}
fun main() {
println(ValidatingProcessor(UpperProcessor()).process("hello"))
}Обёртка коллекции только для чтения
Делегирование упрощает создание обёрток-адаптеров. Здесь мы оборачиваем список, добавляем собственный метод сводки и переадресуем все операции списка.
class SummarizedList(private val inner: List<Int>) : List<Int> by inner {
fun total() = inner.sum()
}
fun main() {
val list = SummarizedList(listOf(1, 2, 3))
println(list.size)
println(list.total())
}Подсчёт вызовов
Декоратор может прозрачно отслеживать показатели, что удобно для мониторинга без изменения настоящей реализации.
interface Service { fun call(): String }
class RealService : Service { override fun call() = "ok" }
class CountingService(private val inner: Service) : Service by inner {
var calls = 0
private set
override fun call(): String {
calls++
return inner.call()
}
}
fun main() {
val s = CountingService(RealService())
s.call(); s.call()
println(s.calls)
}Почему здесь выигрывает делегирование
Создание декораторов с помощью наследования потребовало бы сделать базовый класс open и связало бы каждый декоратор с конкретным классом. Делегирование зависит только от интерфейса, поэтому декораторы остаются слабо связанными и пригодными для композиции.
Контрольный список шаблона
Чтобы создать декоратор с делегированием:
- Примите обёрнутый объект как
private val - Делегируйте интерфейс с помощью
by - Переопределяйте только члены, поведение которых Вы улучшаете
- Вызывайте внутренний объект внутри переопределения
Объединяем всё вместе
Декораторы, адаптеры и прокси естественным образом создаются с помощью делегирования классов. В сочетании с небольшими интерфейсами они позволяют создавать гибкие многослойные системы, которые легко тестировать и расширять.
Быстрая проверка
Проверьте, насколько хорошо Вы понимаете практические шаблоны делегирования.
Итоги
Вы создали практические декораторы с помощью делегирования:
- Обёртки для журналирования, кэширования, проверки и подсчёта
- Объединение декораторов, поскольку каждый реализует один и тот же интерфейс
- Переопределение только улучшенных членов и переадресация остальных
На этом курс делегирования классов завершён.
Часто задаваемые вопросы
Урок «Практические шаблоны» бесплатный?
Да — полный текст урока «Практические шаблоны» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «Практические шаблоны»?
Декораторы с делегированием Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Практические шаблоны»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Ключевое слово by
- Делегирование членам
- Делегирование и наследование
- Практические шаблоны