From 081504b5bb8c843bbce0b50386331d73bbce96c6 Mon Sep 17 00:00:00 2001 From: PeachyCad <348111@mail.ru> Date: Sun, 6 Sep 2026 20:04:04 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D1=8B=20=D1=80=D0=B5=D1=88=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/otus/homework/homework/Coffee.kt | 54 ++++++++------ .../homework/NonEmptyStringDelegate.kt | 12 +-- .../ru/otus/homework/homework/UserProfile.kt | 73 ++++++++++++++++++- .../ru/otus/homework/homework/WithLogging.kt | 2 +- .../ru/otus/homework/homework/processList.kt | 2 +- 5 files changed, 107 insertions(+), 36 deletions(-) diff --git a/src/main/kotlin/ru/otus/homework/homework/Coffee.kt b/src/main/kotlin/ru/otus/homework/homework/Coffee.kt index c73f420..9aa43fb 100644 --- a/src/main/kotlin/ru/otus/homework/homework/Coffee.kt +++ b/src/main/kotlin/ru/otus/homework/homework/Coffee.kt @@ -20,32 +20,38 @@ class SimpleCoffee : Coffee { override fun description() = "Простой кофе" } -class MilkDecorator(private val coffee: Coffee) : Coffee { - override fun cost(): Int { - TODO("Not yet implemented") - } - - override fun description(): String { - TODO("Not yet implemented") - } -} +/** + * Базовый декоратор: хранит оборачиваемый напиток и знает, + * как добавить к нему стоимость и название ингредиента. + * Наследникам остается только объявить свою добавку. + */ +abstract class CoffeeDecorator(private val coffee: Coffee) : Coffee { + /** + * Стоимость добавки в копейках + */ + protected abstract val additionalCost: Int + + /** + * Название добавки для описания напитка + */ + protected abstract val ingredient: String + + override fun cost(): Int = coffee.cost() + additionalCost -class SugarDecorator(private val coffee: Coffee) : Coffee { - override fun cost(): Int { - TODO("Not yet implemented") - } + override fun description(): String = "${coffee.description()}, $ingredient" +} - override fun description(): String { - TODO("Not yet implemented") - } +class MilkDecorator(coffee: Coffee) : CoffeeDecorator(coffee) { + override val additionalCost = 50 + override val ingredient = "молоко" } -class VanillaDecorator(private val coffee: Coffee) : Coffee { - override fun cost(): Int { - TODO("Not yet implemented") - } +class SugarDecorator(coffee: Coffee) : CoffeeDecorator(coffee) { + override val additionalCost = 20 + override val ingredient = "сахар" +} - override fun description(): String { - TODO("Not yet implemented") - } -} \ No newline at end of file +class VanillaDecorator(coffee: Coffee) : CoffeeDecorator(coffee) { + override val additionalCost = 70 + override val ingredient = "ваниль" +} diff --git a/src/main/kotlin/ru/otus/homework/homework/NonEmptyStringDelegate.kt b/src/main/kotlin/ru/otus/homework/homework/NonEmptyStringDelegate.kt index 568f368..ee3b4ca 100644 --- a/src/main/kotlin/ru/otus/homework/homework/NonEmptyStringDelegate.kt +++ b/src/main/kotlin/ru/otus/homework/homework/NonEmptyStringDelegate.kt @@ -5,12 +5,12 @@ import kotlin.reflect.KProperty /** * Delegate that allows to set non-empty string value */ -class NonEmptyStringDelegate() { - operator fun getValue(thisRef: Any?, property: KProperty<*>): String { - TODO("Implement `getValue` function") - } +class NonEmptyStringDelegate(private var value: String = "") { + operator fun getValue(thisRef: Any?, property: KProperty<*>): String = value operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) { - TODO("Implement `setValue` function") + if (newValue.isNotBlank()) { + value = newValue + } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/otus/homework/homework/UserProfile.kt b/src/main/kotlin/ru/otus/homework/homework/UserProfile.kt index f0fab82..7deb895 100644 --- a/src/main/kotlin/ru/otus/homework/homework/UserProfile.kt +++ b/src/main/kotlin/ru/otus/homework/homework/UserProfile.kt @@ -2,6 +2,8 @@ package ru.otus.homework.homework +import kotlin.properties.Delegates + /** * Профиль пользователя */ @@ -36,9 +38,8 @@ interface UserProfile { /** * Creates user profile with logging */ - fun createWithLogging(fullName: String, email: String): UserProfile.Logging { - TODO("Implement `createWithLogging` function") - } + fun createWithLogging(fullName: String, email: String): UserProfile.Logging = + LoggingProfileImplementation(create(fullName, email)) } } @@ -50,4 +51,68 @@ private val emailRegex = Regex("^[A-Za-z](.*)([@])(.+)(\\.)(.+)") /** * Реализация простого [UserProfile]. */ -private class ProfileImplementation(override var fullName: String, override var email: String): UserProfile \ No newline at end of file +private class ProfileImplementation(fullName: String, email: String) : UserProfile { + + override var fullName: String by NonEmptyStringDelegate(fullName) + + override var email: String by Delegates.vetoable(email) { _, _, newValue -> + emailRegex.matches(newValue) + } +} + +/** + * Журнал с возможностью записи. Приватный интерфейс: наружу, через [WithLogging], + * журнал доступен только на чтение. + */ +private interface LogWriter : WithLogging { + fun record(property: String, oldValue: String, newValue: String) +} + +/** + * Журнал изменений. Отдельный класс, чтобы профиль мог делегировать ему [LogWriter]. + */ +private class LogRecorder : LogWriter { + private val entries = mutableListOf() + + override fun getLog(): List = entries.toList() + + override fun record(property: String, oldValue: String, newValue: String) { + entries += "Changing `$property` from '$oldValue' to '$newValue'" + } +} + +/** + * Профиль с логированием: оборачивает готовый [UserProfile] и пишет в журнал + * каждое реально произошедшее изменение свойства. + */ +private class LoggingProfileImplementation( + private val profile: UserProfile, + private val logRecorder: LogRecorder = LogRecorder(), +) : UserProfile.Logging, LogWriter by logRecorder { + + override var fullName: String + get() = profile.fullName + set(value) { + val oldValue = profile.fullName + profile.fullName = value + logIfChanged("fullName", oldValue, profile.fullName) + } + + override var email: String + get() = profile.email + set(value) { + val oldValue = profile.email + profile.email = value + logIfChanged("email", oldValue, profile.email) + } + + /** + * Пишет в журнал, только если значение действительно изменилось: + * делегаты [UserProfile] молча отклоняют некорректные значения. + */ + private fun logIfChanged(property: String, oldValue: String, newValue: String) { + if (newValue != oldValue) { + record(property, oldValue, newValue) + } + } +} diff --git a/src/main/kotlin/ru/otus/homework/homework/WithLogging.kt b/src/main/kotlin/ru/otus/homework/homework/WithLogging.kt index 4a41138..6e55ad0 100644 --- a/src/main/kotlin/ru/otus/homework/homework/WithLogging.kt +++ b/src/main/kotlin/ru/otus/homework/homework/WithLogging.kt @@ -8,4 +8,4 @@ interface WithLogging { * Текущие записи журнала */ fun getLog(): List -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/otus/homework/homework/processList.kt b/src/main/kotlin/ru/otus/homework/homework/processList.kt index 6d8ab43..fa9940e 100644 --- a/src/main/kotlin/ru/otus/homework/homework/processList.kt +++ b/src/main/kotlin/ru/otus/homework/homework/processList.kt @@ -8,7 +8,7 @@ inline fun processList(list: List, action: (Int) -> Unit) { fun skipThreeAndPrint(list: List) { processList(list) { - if (it == 3) return + if (it == 3) return@processList println("Processing $it") } }