C++ 设计模式之装饰模式

【声明】本题目来源于卡码网(题目页面 (kamacoder.com))

【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】


【简介】什么是装饰模式

        通常情况下,扩展类的功能可以通过继承实现,但是扩展越多,⼦类越多,装饰模式( Decorator Pattern , 结构型设计模式)可以在不定义⼦类的情况下动态的给对象添加⼀些额外的功能。具体的做法是将原始对象放⼊包含⾏为的特殊封装类(装饰类),从⽽为原始对象动态添加新的⾏为,⽽⽆需修改其代码。
        举个简单的例⼦,假设你有⼀个基础的图形类,你想要为图形类添加颜⾊、边框、阴影等功能,如果每个功能都实现⼀个⼦类,就会导致产⽣⼤量的类,这时就可以考虑使⽤装饰模式来动态地添加,⽽不需要修改图形类本身的代码,这样可以使得代码更加灵活、更容易维护和扩展。


【基本结构】

        装饰模式包含以下四个主要⻆⾊:

  • 组件Component :通常是抽象类或者接⼝,是具体组件和装饰者的⽗类,定义了具体组件需要实现的⽅法,⽐如说我们定义Coffee 为组件。
  • 具体组件ConcreteComponent : 实现了Component接⼝的具体类,是被装饰的对象。
  • 装饰类Decorator :⼀个抽象类,给具体组件添加功能,但是具体的功能由其⼦类具体装饰者完成,持有⼀个指向Component对象的引⽤。
  • 具体装饰类ConcreteDecorator :扩展Decorator类,负责向Component对象添加新的⾏为,加⽜奶的咖啡是⼀个具体装饰类,加糖的咖啡也是⼀个具体装饰类。

C++ 设计模式之装饰模式_第1张图片


【基本实现】

装饰模式的实现包括以下步骤:(以Java代码做示例)

1. 定义Component接⼝

// 组件接⼝
public interface Component {
    void operation();
}

2. 实现 ConcreteComponent

// 具体组件
public class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent operation");
    }
}

3. 定义Decorator装饰类,继承⾃Component

// 定义⼀个抽象的装饰者类,继承⾃Component
public abstract class Decorator implements Component {
    protected Component component;
    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

4. 定义具体的装饰者实现,给具体组件对象添加功能。

// 具体的装饰者实现
public class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }
// 根据需要添加额外的⽅法
    @Override
    public void operation() {
        // 可以在调⽤前后添加额外的⾏为
        System.out.println("Before operation in ConcreteDecorator");
        super.operation();
        System.out.println("After operation in ConcreteDecorator");
    }
}

5. 在客户端使⽤

public class Main {
    public static void main(String[] args) {
        // 创建具体组件
        Component concreteComponent = new ConcreteComponent();
        // 使⽤具体装饰者包装具体组件
        Decorator decorator = new ConcreteDecorator(concreteComponent);
        // 调⽤操作
        decorator.operation();
    }
}

【应用场景】

        装饰模式通常在以下⼏种情况使⽤:

  • 当需要给⼀个现有类添加附加功能,但由于某些原因不能使⽤继承来⽣成⼦类进⾏扩充时,可以使⽤装饰模式。
  • 动态的添加和覆盖功能:当对象的功能要求可以动态地添加,也可以再动态地撤销时可以使⽤装饰模式。

        在Java的I/O库中,装饰者模式被⼴泛⽤于增强I/O流的功能。例如, BufferedInputStream 和
BufferedOutputStream 这两个类提供了缓冲区的⽀持,通过在底层的输⼊流和输出流上添加缓冲区,提⾼了读写的效率,它们都是InputStream 和OutputStream 的装饰器。BufferedReader 和BufferedWriter 这两个类与BufferedInputStream 和BufferedOutputStream 类似,提供了字符流的缓冲功能,是Reader和Writer的装饰者。



【编码部分】

1. 题目描述

        小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。 

        请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。

2. 输入描述

        多行输入,每行包含两个数字。第一个数字表示咖啡的选择(1 表示黑咖啡,2 表示拿铁),第二个数字表示要添加的调料类型(1 表示牛奶,2 表示糖)。

3. 输出描述

        根据每行输入,输出制作咖啡的过程,包括咖啡类型和添加的调料。

4. C++编码实例


/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file DecoratorMode.hpp
* @brief 装饰模式
* @autor 写代码的小恐龙er
* @date 2024/01/11
*/

#include 
#include 

using namespace std;
// 前置声明
// 抽象的基类 -- 接口类
class Coffee;
// 具体的黑咖啡类
class BlackCoffee;
// 具体的拿铁类
class Latte;
// 装饰者抽象类 -- 接口类的派生类
class Decorator;
// 具体的牛奶装饰类 -- Decorator的派生类
class MilkDecorator;
// 具体的糖装饰类 -- Decorator的派生类
class SugarDecorator;

// 抽象的基类 -- 接口类
class Coffee
{
public:
    virtual void PrintInfo() = 0;
};

// 具体的黑咖啡类
class BlackCoffee : public Coffee
{
 public:
    // 重载接口函数
    void PrintInfo() override
    {
        std::cout << "Brewing Black Coffee" << endl;
    }
};

// 具体的拿铁类
class Latte : public Coffee
{
 public:
    // 重载接口函数
    void PrintInfo() override
    {
        std::cout << "Brewing Latte" << endl;
    }
};

// 装饰者抽象类 -- 接口类的派生类
class Decorator : public Coffee
{
protected:
    // 持有一个抽象接口类的对象
    Coffee *_coffee;
public:
    // 构造函数重载
    // 当派生类重载了构造函数时 基类需要定义默认构造函数
    Decorator(){}
    Decorator(Coffee *coffee){
        this->_coffee = coffee;
    }
    
    // 重载抽象类的接口函数
    void PrintInfo() override {
        _coffee->PrintInfo();
    }
};

// 具体的牛奶装饰类 -- Decorator的派生类
class MilkDecorator: public Decorator
{
public:
    // 持有一个装饰类的对象
    Decorator *_decorator;
public:
    // 构造函数重载
    MilkDecorator(Decorator *decorator){
        this->_decorator = decorator;
    }
    
    // 重载抽象类的接口函数
    void PrintInfo() override {
        _decorator->PrintInfo();
        std::cout << "Adding Milk" << endl;
    }   
};

// 具体的糖装饰类 -- Decorator的派生类
class SugarDecorator : public Decorator
{
public:
    // 持有一个装饰类的对象
    Decorator *_decorator;
public:
    // 构造函数重载
    SugarDecorator(Decorator *decorator){
        this->_decorator = decorator;
    }
    
    // 重载抽象类的接口函数
    void PrintInfo() override {
        _decorator->PrintInfo();
        std::cout << "Adding Sugar" << endl;
    }   
};

int main()
{
    // 咖啡类型
    int coffeeType = 0;
    // 调料类型
    int seasoningType = 0;
    while(std::cin >> coffeeType >> seasoningType)
    {
        Coffee *coffee = nullptr;
        // 咖啡类型
        if(coffeeType == 1){
            coffee = new BlackCoffee();
        }
        else if (coffeeType == 2){
            coffee = new Latte();
        }
        else return 0;
        
        Decorator *decorator = new Decorator(coffee);
        
        // 调料类型
        if(seasoningType == 1){
            coffee = new MilkDecorator(decorator);
        }
        else if (seasoningType == 2){
            coffee = new SugarDecorator(decorator);
        }
        else return 0;
        
        // 输出制作过程
        coffee->PrintInfo();
        
        
        delete decorator;
        decorator = nullptr;
        delete coffee;
        coffee = nullptr;
    }
    return 0;
}


......

To be continued.

你可能感兴趣的:(设计模式,c++,装饰器模式,java)