更多设计模式参看: 设计模式之模式概述(模式汇总)(C++实现)
文章目录
介绍
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
意图:
装饰模式(Decorator Pattern): 动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
解决问题:
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。
实现概述:
使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能。
要点:
装饰模式的核心在于抽象装饰类的设计,抽象装饰类(装饰器类)和原始类继承同样的父类,这样可以对原始类“嵌套”多个装饰器类。抽象装饰类(装饰器类)是对功能的增强,这也是装饰器模式应用场景的一个重要特点。并且抽象装饰类维持一个对抽象构件对象的引用component,抽象装饰类可以通过构造函数或Setter方法注入一个抽象构件类型的对象。
应用场景:
(1) 在不影响其他对象的情况下,给单个对象动态扩展职责;
(2) 不适宜采用继承的方式进行扩展的时候,可以考虑使用装饰模式。
比如 Java IO类库
优点:
(1) 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。
(2) 可以通过一种动态的方式来扩展一个对象的功能。
(3) 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合进行多次装饰。
(4) 具体构件类与具体装饰类可以独立变化,符合“开闭原则”。
缺点:
(1) 装饰模式中会增加很多小的对象,对象的区别主要在于各种装饰的连接方式不同,而并不是职责不同,大量小对象的产生会占用较多的系统资源;
(2) 装饰模式比继承模式更灵活,但也更容易出错,更难于排错。
模式结构
角色
-
Component(抽象构件): 它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,使客户端能够以一致的方式处理未被装饰的对象以及装饰之后的对象。
-
ConcreteComponent(具体构件): 它是抽象构件类的子类,实现了在抽象构件中声明的方法,装饰器就是为它增加额外的功能(方法)。
-
Decorator(抽象装饰类): 它也是抽象构件类的子类,用于给具体构件增加功能,但是具体功能在它的子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用构件对象的方法,并通过其子类(具体装饰类)扩展该方法,以达到装饰的目的。
-
ConcreteDecorator(具体装饰类): 它是抽象装饰类的子类,负责向构件添加新的功能。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
类图
代码示例
今天上班途中在路边的小车车那买了个手抓饼作为早餐,商家价格,基础3元版,基础5元版,加鸡蛋1.5元,加火腿肠1元,加青菜0.5元 等,由于没钱只好买了个基础3元版的╮(╯▽╰)╭。可以使用装饰器模式来表示购买不同组合的手抓饼。
Component(抽象构件): HandPancake
ConcreteComponent(具体构件): ConcreteHandPancake
Decorator(抽象装饰类):Decorator
ConcreteDecorator(具体装饰类):addEgg , addSausage , addVegetable
GitHub
Component(抽象构件)
/// Component(抽象构件): HandPancake
class HandPancake {
public:
virtual ~HandPancake() = default;
virtual std::string offerHandPancake() = 0; // 制作手抓饼
virtual float calcPrice() = 0; // 计算价格
protected:
HandPancake() = default;
};
ConcreteComponent(具体构件)
enum TYPE {
Base3 = 3,
Base5 = 5,
};
/// ConcreteComponent(具体构件): ConcreteHandPancake
class ConcreteHandPancake : public HandPancake {
public:
explicit ConcreteHandPancake(TYPE price) {
std::cout <<