设计模式(5):C++装饰模式

目录

简介

动机

适用性

结构

装饰模式的参与者

效果

注意点

实例

UML图

代码与函数

代码

总结

简介

动态地给一个对象添加一些额外的职责。
就增加功能来说,装饰模式比生成子类更为灵活。

动机

有时我们希望给某个对象而不是整个类添加一些功能。
使用继承机制是添加功能的一种有效途径,但不够灵活,用户不能控制对组件添加功能的方式和时机。
一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加功能,我们称这个嵌入的对象为装饰。
这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。

适用性

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
处理那些可以撤销的职责。
当不能采用生成子类的方法进行扩充时。
可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
类定义被隐藏,或类定义不能用于生成子类。

结构

在这里插入图片描述

装饰模式的参与者

Component
定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent
定义一个对象,可以给这个对象添加一些职责。
Decorator
维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
ConcreteDecorator
向组件添加职责。

装饰模式的协作
Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加动作。

效果

比静态继承更灵活
避免在层次结构高层的类有太多的特征
Decorator与它的Component不一样
有许多小对象

注意点

如果只有一个ConcreteComponent类而没有Component类,那么Decorator类可以是ConcreteComponent的一个子类。
同理,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator合并成一个类。

实例

给定两种初始的汽车类,例如丰田和沃尔沃,利用装饰模式分别给它们添加新的功能,其中丰田可以导航和自动驾驶,沃尔沃可以导航和语音控制。

UML图

在这里插入图片描述

代码与函数

Component:Car类

ConcreteComponent:TOYOTA、VOLOVO类

Decorator:Function类

ConcreteDecorator:Navigator、SelfDrive、VoiceControl类

代码

#include<iostream>
using namespace std;
 
/*
给定两种初始的汽车类,例如丰田和沃尔沃,
利用装饰模式分别给它们添加新的功能,
其中丰田可以导航和自动驾驶,沃尔沃可以导航和语音控制。
*/
 
class Car{//Component
public:
    virtual void showInfo() = 0;
};
 
class TOYOTA: public Car{
public:
    TOYOTA(){}
    TOYOTA(string name){
        this->name = name;
    }
    void showInfo(){
        cout<<name<<endl;
    }
private:
    string name;
};
 
class  VOLOVO: public Car{
public:
    VOLOVO(){}
    VOLOVO(string name){
        this->name = name;
    }
    void showInfo(){
        cout<<name<<endl;
    }
private:
    string name;
};
 
class Function: public Car{//Decorator
protected:
    Car* car;
public:
    void Decorate(Car* car){
        this->car = car;
    }
    void showInfo(){
        if(car != NULL)car->showInfo();
    }
};
 
//其中丰田可以导航和自动驾驶,沃尔沃可以导航和语音控制。
 
class Navigator: public Function{
public:
    void showInfo(){
        cout<<"导航 ";
        Function::showInfo();
    }
};
 
class SelfDrive: public Function{
public:
    void showInfo(){
        cout<<"自动驾驶 ";
        Function::showInfo();
    }
};
 
class VoiceControl: public Function{
public:
    void showInfo(){
        cout<<"语音控制 ";
        Function::showInfo();
    }
};
 
 
//其中丰田可以导航和自动驾驶,沃尔沃可以导航和语音控制。
int main(){
    Car* toyota = new TOYOTA("丰田卡罗拉");
    Navigator* na = new Navigator();
    SelfDrive* sd = new SelfDrive();
    na->Decorate(toyota);
    sd->Decorate(na);
    sd->showInfo();
    cout<<endl;
    
    Car* volovo = new VOLOVO("沃尔沃S90");
    Navigator* na2 = new Navigator();
    VoiceControl* vc = new VoiceControl();
    na2->Decorate(volovo);
    vc->Decorate(na2);
    vc->showInfo();
 
    return 0;
}

总结

①本次实验通过Car的实例掌握并编码了装饰模式。

②注意如果只有一个ConcreteComponent类而没有Component类,那么Decorator类可以是ConcreteComponent的一个子类。在本次实验中,有TOYOTA和VOLOVO两个具体的类,因此需要一个Component的Car类来定义接口。

③由②可知,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator合并成一个类。在本次实验中有Navigator、SelfDrive、VoiceControl三个具体的装饰类。

④在客户端中,要最后一个添加的职责,用来是包装好了的车对象,因此需要由最后一个装饰的实例显示结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值