设计模式之装饰设计模式
一、装饰设计模式概念
装饰模式 (Decorator) 是一种结构型设计模式,动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。
- 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
- 装饰对象包含一个真实对象的引用(reference)。
- 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
- 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
适用场景
- 如果你希望在无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式。
- 如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。
组合设计模式的结构:
- 部件 (Component) 声明封装器和被封装对象的公用接口。
- 具体部件 (Concrete Component) 类是被封装对象所属的类。 它定义了基础行为, 但装饰类可以改变这些行为。
- 基础装饰 (Base Decorator) 类拥有一个指向被封装对象的引用成员变量。 该变量的类型应当被声明为通用部件接口, 这样它就可以引用具体的部件和装饰。 装饰基类会将所有操作委派给被封装的对象。
- 具体装饰类 (Concrete Decorators) 定义了可动态添加到部件的额外行为。 具体装饰类会重写装饰基类的方法, 并在调用父类方法之前或之后进行额外的行为。
- 客户端 (Client) 可以使用多层装饰来封装部件, 只要它能使用通用接口与所有对象互动即可。
代码如下:
问题:饮料店订单系统,饮料有咖啡、奶茶、果汁,饮料可以加糖、加奶、加冰。
解决方案:动态的给饮料添加新的功能,而不需要修改饮料的代码。就增加功能来说,装饰模式比继承更加灵活。找出基本组件和可选层次。
#include<iostream>
#include<string>
//接口:具体被包裹的类,以及装饰类
class Beverage
{
public:virtual ~Beverage() {}virtual std::string Operation()const = 0;};
//具体类:被装饰的类
class Americano :public Beverage
{
public:~Americano() {}std::string Operation()const{return "Americano";}
};
//装饰类:给被装饰的类添加新的功能
//基础部分(可能包括额外部分)
class Ingredient :public Beverage
{
protected:Beverage* m_beverage;
public:~Ingredient() {}Ingredient(Beverage* beverage) :m_beverage(beverage) {}std::string Operation()const override{return m_beverage->Operation();//核心代码,不是用来被基类覆盖的}
};
//额外部分(需要委托基类,完成基础部分)
class Whip : public Ingredient
{
public:~Whip() {}Whip(Beverage* beverage):Ingredient(beverage) {}std::string Operation()const override{//在基类的operation之前,之后都可以增加额外的操作return "(奶昔" + m_beverage->Operation() + ")";}
};class Mocha : public Ingredient
{
public:~Mocha() {}Mocha(Beverage* beverage) :Ingredient(beverage) {}std::string Operation()const override{//在基类的operation之前,之后都可以增加额外的操作return "(摩卡" + m_beverage->Operation() + ")";}
};
void ClientCode(Beverage* beverage)
{std::cout<<"执行结果:"<<beverage->Operation()<<std::endl;
}int main()
{Beverage* americano = new Americano();ClientCode(americano);std::cout << "添加2摩卡+奶昔" << std::endl;Beverage* whip = new Whip(americano);Beverage* mocha1 = new Mocha(whip);Beverage* mocha2 = new Mocha(mocha1);ClientCode(mocha2);delete mocha2;delete mocha1;delete whip;delete americano;return 0;
}