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

发布时间:2024年01月16日

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

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


【简介】什么是装饰模式

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


【基本结构】

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

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


【基本实现】

装饰模式的实现包括以下步骤:(以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 <iostream>
#include <string>

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.

文章来源:https://blog.csdn.net/K1_uestc/article/details/135523891
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。