[Серия «Учимся вместе»] Режим декоратора: не менять функцию улучшения кода?

Шаблоны проектирования
[Серия «Учимся вместе»] Режим декоратора: не менять функцию улучшения кода?

намерение

Динамически добавлять дополнительные обязанности к объекту.С точки зрения добавления функциональности шаблон Decorator более гибок, чем генерация подклассов.

Псевдоним: Обертка

Рождение шаблона декоратора

Иногда мы хотим добавить некоторые функции к объекту, а не ко всему классу, например: набор инструментов GUI позволяет добавлять некоторые функции, такие как границы, к любому компоненту пользовательского интерфейса.

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

Речь это:

[Продукт]: Разработчик, у меня тут есть код. Вам нужно вызвать его функции и дополнить дополнительные функции компании, но вы не можете изменить его собственное содержание. Сможете ли вы это сделать?

【Развитие】: А? как это возможно! Как можно иметь другие функции без изменения кода и иметь дополнительные функции? Хочешь, чтобы я так написал?

void demo () {
    // 调用原有代码功能
    // do();
    
    // 调用公司功能
    // doMine();
}

【БОСС】: Низкий поклон! Вам не кажется, что это очень мало?

[В разработке]: Но как я могу переписать это, если я не напишу это так?

[БОСС]: Посмотрите внимательно на исходный код, все они реализуют один и тот же интерфейс, это точка прорыва

[Развитие]: Я собираюсь исследовать....

Основной код HeadFirst

Итак, мы начали путешествие с чтения классических книг о шаблонах проектирования.

/**
 * 装饰器模式共同的接口
 */
public interface Component {
    String getName();
    double getSpend();
}


/**
 * 原本的类
 */
public class ConcreteComponent implements Component {

    private String name;

    public ConcreteComponent(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getSpend() {
        return 10;
    }
}


/**
 * 装饰器类 注意它利用了组合的方式,同时注意函数实现的部分
 */
public class MilkDecorator implements Component {

    Component coffe;

    MilkDecorator(Component coffe) {
        this.coffe = coffe;
    }

    @Override
    public String getName() {
       return coffe.getName() + ", 牛奶";
    }

    @Override
    public double getSpend() {
        return coffe.getSpend() + 2D;
    }
}

Идеи оформления узора декоратор:

  • Компонент: определяет интерфейс объекта, унифицированное поведение и родителя.
  • ConcreteComponent: определите объект, к которому вы можете добавить некоторые обязанности (методы)
  • Декоратор (необязательно): определите интерфейс, совместимый с компонентом, и ограничьте обязанности (методы), которые необходимо реализовать.
  • ConcreteDecorator: поддерживает указатель на объект Component и реализует интерфейс Component для улучшения поведения объекта.

Проще говоря,

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

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

Принципы дизайна, которым нужно следовать

  1. "Открыт для расширения, закрыт для модификации": Отлично достигает цели усовершенствования метода без изменения его кода.
  2. "Программирование для интерфейса": декоратор имеет того же родителя, что и он сам

Какая сцена подходит для использования

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

Код / практическое применение в жизни

Самое известное применение шаблона декоратора в Java — классы реализации различных InputStream, Reader и Writer в пакете java.io. Если мы хотим прочитать текстовое содержимое из файла, мы можем использовать FileReader (декоратор) и FileInputStream (декоратор);

Но если мы хотим сделать чтение быстрее, то нам нужен BufferedReader (декоратор), чего можно добиться изменением всего одной строчки кода

Наконец

"Прикрепите диаграмму UML для шаблона декоратора в книге GOF:"

装饰器模式UML图
UML-диаграмма шаблона декоратора

Связанные ссылки на код

Адрес GitHub

  • С учетом случаев в двух классических данных "HeadFirst" и "GOF"
  • Предоставляет дружественное руководство по чтению