• 设计模式:装饰器模式(C++实现)


    设计模式:装饰器模式(C++实现)

    1. 前言

    首先先上结论:装饰器模式的设计场景是为已有的类增加新的功能。

    有人可能会觉得有些奇怪:增加新的功能可以通过继承的方式进行实现。例如,我通过public继承把父类的东西全部继承过来,接口也全部继承过来,然后在子类的基础上增加新的接口不就行了?

    其实理论上确实是可以的,但是这种方式通过继承+增加功能(接口)的方式在某些情况下可能会存在冗余,而装饰器的设计模式可以减少这种冗余。例如,假设现在有两个个汽车的厂家:BWM、Benz。在一开始,汽车只有最原始的功能,但是通过技术的革新,两个汽车的厂家都增加了“定速巡航”、“自动刹车”这两个功能。

    在理论上,要增加这两个功能,可以在原有类的基础上,继承+拓展来实现。但是仔细一想,这样需要重写四个类,分别是:原始宝马+定速巡航、原始宝马+自动刹车、原始奔驰+定速巡航、原始奔驰+自动刹车。这里可以看见,需要增加的子类是比较多的,此外,我们能隐隐的感觉到这种设计方法可能存在一些冗余:能不能把“定速巡航”、“自动刹车”抽象出来,再通过某个方式和原始的汽车结合来完成功能的拓展?

    这么想的话,就已经基本上把装饰器模式的核心掌握了。如果是在这个案例中使用装饰器模式的话,就是只需要设计两个装饰器类就可以了。然后把原始的对象丢进这个装饰器中,就会返回一个增加了新功能的对象。

    2. 实现

    这里我们先实现两个汽车类,他们都来自虚基类Car。

    class Car {
    public:
    	virtual void show() = 0;
    };
    
    class BMW : public Car {
    public:
    	void show() {
    		cout << "This is a BMW! Function: Base Function ";
    	}
    };
    
    class Benz : public Car {
    public:
    	void show() {
    		cout << "This is a Benz! Function: Base Function ";
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这些汽车只实现了基础的功能,如果使用继承的方式来增加功能,不同的类添加了下相同的功能,就比较冗余。因此,下面使用两个装饰器来各自抽象出某个功能:

    class Decocrator01 : public Car {
    public:
    	Decocrator01(Car* c) : obj_(c) {}
    	
    	// 装饰器1为传进来的car增加了定速巡航的功能
    	void show() {
    		obj_->show();
    		cout << "Cruise control " ;
    	}
    
    private:
    	Car* obj_;
    };
    
    class Decocrator02 : public Car {
    public:
    	Decocrator02(Car* c) : obj_(c) {}
    
    	// 装饰器2为传进来的car增加了定速巡航的功能
    	void show() {
    		obj_->show();
    		cout << "Automatic brake " ;
    	}
    
    private:
    	Car* obj_;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    可以看见,装饰器的设计就是开放了一个接口来接收一个只具有原始功能的对象。在实际做事的时候,原始功能部分使用了原来的旧接口,添加的功能在旧接口的下面。这样,只要传进来的对象是Car类型就可以了,而不需要考虑你在不同类型的Car都拓展相同的、冗余的功能。下为测试用例:

    int main() {
    
    	// 原始功能
    	Car* c1 = new BMW();
    	c1->show();
    	cout << endl;
    
    	// 使用装饰器1为车辆增加定速巡航功能
    	c1 = new Decocrator01(c1);
    	c1->show();
    	cout << endl;
    
    	// 使用装饰器2为车辆增加自动刹车功能
    	c1 = new Decocrator02(c1);
    	c1->show();
    	cout << endl;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    全部代码:

    #include 
    
    using namespace std;
    
    class Car {
    public:
    	virtual void show() = 0;
    };
    
    class BMW : public Car {
    public:
    	void show() {
    		cout << "This is a BMW! Function: Base Function ";
    	}
    };
    
    class Benz : public Car {
    public:
    	void show() {
    		cout << "This is a Benz! Function: Base Function ";
    	}
    };
    
    
    class Decocrator01 : public Car {
    public:
    	Decocrator01(Car* c) : obj_(c) {}
    	
    	// 装饰器1为传进来的car增加了定速巡航的功能
    	void show() {
    		obj_->show();
    		cout << "Cruise control " ;
    	}
    
    private:
    	Car* obj_;
    };
    
    class Decocrator02 : public Car {
    public:
    	Decocrator02(Car* c) : obj_(c) {}
    
    	// 装饰器2为传进来的car增加了定速巡航的功能
    	void show() {
    		obj_->show();
    		cout << "Automatic brake " ;
    	}
    
    private:
    	Car* obj_;
    };
    
    
    int main() {
    
    	// 原始功能
    	Car* c1 = new BMW();
    	c1->show();
    	cout << endl;
    
    	// 使用装饰器1为车辆增加定速巡航功能
    	c1 = new Decocrator01(c1);
    	c1->show();
    	cout << endl;
    
    	// 使用装饰器2为车辆增加自动刹车功能
    	c1 = new Decocrator02(c1);
    	c1->show();
    	cout << endl;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    运行结果:
    在这里插入图片描述

  • 相关阅读:
    2023Node.js零基础教程(小白友好型),nodejs新手到高手,(一)NodeJS入门
    Mac实现Gitlab CICD
    UnitTest框架
    3.下载Swin-Transformer-Object-Detection
    所有人喝完咖啡并洗完咖啡杯,至少来到时间点
    Qt的委托代理机制
    CentOS + Caddy + DNSPod(腾讯云)
    一种基于混合策略的灰狼优化算法-附代码
    通讯网关软件029——利用CommGate X2MQTT实现MQTT访问DDE数据源
    python 运算符的优先级:先算乘除,后算加减,有括号的先算括号里面的。
  • 原文地址:https://blog.csdn.net/zsiming/article/details/126691843