Что такое шаблон декоратора?

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

Что такое Dделегирование?

Шаблон делегирования — это объектно-ориентированный шаблон проектирования, который позволяет при композиции объектов добиваться того же повторного использования кода, что и наследование.

Покажи мне код!

Давайте разберем шаблон декоратора на примере. У нас есть класс UserRepositoryImpl, который реализует UserRepository. UserRepositoryImpl и предоставляет функциональные возможности для получения и добавления пользователей.

interface UserRepository {
    fun get(userName:String):String?
    fun set(userName: String,user:String)
}
class UserRepositoryImpl : UserRepository {

    private val userList: MutableMap<String, String> =
        mutableMapOf("superman" to "Clark Kent", "batman" to "Bruce Wayne")

    override fun get(userName: String): String? {
        return userList[userName]
    }

    override fun set(userName: String, user: String) {
        userList[userName] = user
    }
}

Теперь предположим, что вы хотите добавить проверку длины для имени пользователя без изменения поведения и структуры существующего объекта.

Мы используем класс декоратора. Воспользовавшись преимуществами Kotlin, мы можем создать декоратор с нулевым шаблоном. Для этого Kotlin предоставляет byделегатов. Обратите внимание, что мы не изменяем UserRepositoryImpl

class UsernameValidator (private val repository: UserRepository) : UserRepository by repository{

    override fun set(userName: String, user: String) {
        require(userName.length in MIN_NAME_LENGTH..MAX_NAME_LENGTH){
            "user name is not of valid length"
        }
        repository.set(userName,user)
    }

    companion object{
        private const val MAX_NAME_LENGTH = 20
        private const val MIN_NAME_LENGTH = 4
    }
}

Применение

val userRepository = UserRepositoryImpl()
val userValidator = UsernameValidator(userRepository)
userValidator.get(userName)

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

Да, мы можем использовать наследование, но обычно мы идем к наследованию, когда у нас есть четкие и стабильные отношения между классами, которые имеют общие атрибуты и поведение.
Используя декоратор, мы создаем объект-оболочку с существующим объектом, не создавая новый подтип. объекта. мы можем использовать шаблон декоратора для создания различных вариантов поведения во время выполнения в зависимости от контекста или предпочтений пользователя.

Некоторыми из распространенных вариантов использования шаблонов декораторов являются функции ведения журнала, кэширования, шифрования или проверки объекта без изменения его исходного поведения.

Примечание. На что следует обратить внимание, прежде чем переходить к шаблону декоратора

  1. Нам нужно иметь возможность получать украшаемый объект.
  2. Нам нужна возможность сохранить ссылку на объект.
  3. Нам нужна возможность извлечь интерфейс или предоставить его.

Бонус

Мы можем добавить ключевое слово operator в определения функций UserRepository.

interface UserRepository {
    operator fun get(userName:String):String?
    operator fun set(userName: String,user:String)
}

Теперь мы можем воспользоваться преимуществами синтаксического сахара Kotlin, мы можем использовать наш UserRepository вот так.

 repository[userName] = user   // set 
 repository[userName]         // get

удачного кодирования 😊

Читайте о сопрограммах здесь: