文章目录
- 1.定义
- [2. 结构组成](#2. 结构组成)
- [3. 组合模式结构](#3. 组合模式结构)
- [4. 示例代码](#4. 示例代码)
- [5. 模式优势](#5. 模式优势)
- [6. 应用场景](#6. 应用场景)
1.定义
装饰模式就像是给你的对象穿上不同的 "时尚服装",在程序运行时,你可以随意地给对象搭配各种 "服装" 来增加新的功能,而且完全不用对对象本身的 "身材"(类结构)进行修改。这是一种很巧妙的设计模式,能够让对象在不改变自身本质的情况下,变得更加 "华丽"。
2. 结构组成
- Component(组件):
- 这就好比是一个标准的 "衣架",它定义了所有可以被装饰的对象的基本 "穿搭风格"(行为)。在装饰模式里,这个 "衣架" 接口有一个 "execute ()" 方法,这就像是所有衣服(具体组件和装饰器)都要能挂在这个衣架上的基本要求。
- Concrete Component(具体组件):
- 这是一件最基础的 "衣服",它按照 "衣架"(Component)的标准制作出来,提供了最基础的 "穿搭效果"(实现了 "execute ()" 方法),代表了对象最原始的功能。
- Base Decorator(基础装饰器):
- 这是一个特别的 "衣架外套",它本身也是按照 "衣架" 的标准制作的(实现了 Component 接口)。它里面还藏着一个对其他 "衣服"(Component 对象)的引用,当你穿上这个 "衣架外套" 时,它会把里面的 "衣服" 也展示出来(在其 "execute ()" 方法中调用 "wrappee" 的 "execute ()" 方法)。
- Concrete Decorators(具体装饰器):
- 这些就像是各种各样的 "时尚配饰",它们都继承自 "衣架外套"(Base Decorator)。当你把这些 "配饰" 挂在 "衣架" 上时,它们可以在展示里面 "衣服"(调用被装饰对象的方法)的前后,添加一些额外的 "时尚元素"(额外的行为)。
3. 组合模式结构
- 创建基础对象:就像你要开始搭配穿搭一样,首先你有了一件基础的 "衣服"(客户端创建一个具体组件对象,例如a = new ConcComponent()),这是最基础的穿搭风格。
- 添加装饰器 :接着,你可以给这件基础 "衣服" 搭配上一件 "衣架外套",比如 "时尚配饰 1"(b = new ConcDecorator1(a),这里 "ConcDecorator1" 是一个具体装饰器,它包装了基础对象 "a")。
你还可以继续在外面添加更多的 "时尚配饰",像 "时尚配饰 2"(c = new ConcDecorator2(b),这里 "ConcDecorator2" 又包装了 "b",形成了一个装饰器链),让你的穿搭变得更加独特。 - 执行操作: 最后,当你穿上这套精心搭配的 "衣服"(调用最外层装饰器的 "execute ()" 方法,如c.execute())时,会按照从外到内的顺序展示出每一件 "衣服" 和 "配饰" 的效果:
- 首先,"时尚配饰 2"("ConcDecorator2")会展示它的 "时尚元素",它可能会在展示里面 "衣服"(调用被装饰对象 "b" 的方法)之前或之后添加一些独特的风格。
- 然后,"时尚配饰 1"("ConcDecorator1")也会展示它的特色,同样可能添加额外的时尚效果。
- 最后,基础的 "衣服"("a")的效果会被展示出来,完成整个 "时尚穿搭秀"(操作)。
4. 示例代码
cpp
#include <iostream>
#include <memory>
using namespace std;
class Component{
public:
Component(){cout << "Component Constructor " <<endl;}
virtual ~Component(){cout << "Component Destructor " <<endl;}
virtual string Operation() const = 0;
};
class ConcreteComponent : public Component{
public:
ConcreteComponent(){cout << "ConcreteComponent Constructor " <<endl;}
~ConcreteComponent(){cout << "ConcreteComponent Destructor " <<endl;}
string Operation() const override{
return "ConcreteComponent";
}
};
class Decorator : public Component{
protected:
shared_ptr<Component> component_;
public:
Decorator(shared_ptr<Component> component) : component_ (component){
cout << "Decorator Constructor " <<endl;
}
~Decorator(){cout << "Decorator Destructor " <<endl;}
string Operation() const override{
return component_->Operation();
}
};
class ConcreteDecoratorA : public Decorator{
public:
ConcreteDecoratorA(shared_ptr<Component> component) : Decorator (component){
cout << "ConcreteDecoratorA Constructor " <<endl;
}
~ConcreteDecoratorA(){cout << "ConcreteDecoratorA Destructor " <<endl;}
string Operation() const override{
return "ConcreteDecoratorA(" + Decorator::Operation() + ")";
}
};
class ConcreteDecoratorB : public Decorator{
public:
ConcreteDecoratorB(shared_ptr<Component> component) : Decorator(component){
cout << "ConcreteDecoratorB Constructor " <<endl;
}
~ConcreteDecoratorB(){cout << "ConcreteDecoratorB Destructor " <<endl;}
string Operation() const override{
return "ConcreteDecoratorB(" + Decorator::Operation() + ")";
}
};
void ClientCode(shared_ptr<Component> component){
cout<< component->Operation() <<endl;
}
int main()
{
shared_ptr<Component> simple = make_shared<ConcreteComponent>();
cout << "Client: I've got a simple component:\n";
ClientCode(simple);
cout << "\n\n";
shared_ptr<Component> decorator1 = make_shared<ConcreteDecoratorA>(simple);
shared_ptr<Component> decorator2 = make_shared<ConcreteDecoratorB>(decorator1);
cout << "Client: Now I've got a decorated component:\n";
ClientCode(decorator2);
std::cout << "\n";
return 0;
}
5. 模式优势
- 灵活性高
- 这种模式就像你的时尚穿搭可以随时变化一样,在程序运行时,你可以动态地给对象添加或移除各种 "时尚元素"(功能),完全不用改变对象本身的 "身材"(结构)。比如,你可以根据当天的心情或者场合,随意地给对象搭配不同的功能。
- 可扩展性好
- 当你想要一种新的 "时尚风格"(功能)时,只需要轻松地设计一个新的 "时尚配饰"(装饰器)就可以了,完全符合程序设计中的 "开闭原则"。这就好比你想要一种新的穿搭风格,只需要买一个新的配饰,而不用重新设计一件衣服。
- 复用性强
- 无论是基础的 "衣服"(组件)还是各种 "时尚配饰"(装饰器),都可以被重复使用,大大减少了代码的重复。就像你可以用同一件基础衣服搭配不同的配饰,或者把同一个配饰用在不同的穿搭上。
6. 应用场景
- 动态添加功能
- 当你在程序中需要像在穿搭中根据心情或场合动态地给对象添加新功能时,装饰模式就非常有用了。例如,在图形用户界面(GUI)中,你可以像给窗口搭配不同的 "时尚元素" 一样,给窗口添加边框、滚动条等装饰。
- 避免类爆炸
- 当你发现如果用传统的继承方式来给对象添加功能,会导致像衣柜里堆满了各种相似但又略有不同的衣服一样(类爆炸),装饰模式就可以通过像搭配穿搭一样的组合方式来替代继承,更加灵活地扩展功能。
- 多特性组合
- 当你有很多像时尚配饰一样的特性需要组合到一个对象上,而且这些特性可以像穿搭一样动态地添加或移除时,装饰模式就派上用场了。比如在咖啡制作系统中,咖啡就像基础的衣服,而糖、奶、巧克力等配料就像各种时尚配饰,每种配料都可以看作是一个装饰器,你可以根据自己的口味随意搭配。