27.1 代理模式 VS 装饰模式
27.1.1 代理模式
(1)场景:客人找运动员代理要求安排运动员参加比赛
(2)说明:代理人有控制权,可以拒绝客人的要求,也可以答应安排,甚至自己下去跑(因为有些运动员本身就作自己的代理)
【编程实验】找代理安排运动员比赛
//结构型模式大PK——代理模式和装饰模式 //实例:找代理安排运动员比赛 #include <iostream> #include <ctime> using namespace std; //抽象运动员 class IRunner { public: virtual void run() = 0; virtual ~IRunner() {} }; //运动员 class Runner : public IRunner { public: void run() { cout << "运动员跑步,动作很潇洒" << endl; } }; //代理人(也与运动员一样,实现同一接口) class RunnerAgent : public IRunner { Runner* runner; public: RunnerAgent(Runner* runner) { srand((int)time(NULL)); this->runner = runner; } void run() { if((rand() % 2) ==0) { cout << "代理人同意安排运动员跑步" << endl; runner->run(); } else { cout << "代理人心情不好,不安排运动员跑步" << endl; } } }; int main() { //定义一个运动员 Runner* runner = new Runner(); //定义代理人 IRunner* agent = new RunnerAgent(runner); //要求运动员跑步 cout << "===客人找到代理要求运动员去跑步" << endl; //为演示,比如洽谈了10次 for(int i=0; i<10; i++) { cout <<"第" <<i+1 <<"次洽谈结果:"; agent->run(); cout << endl; } delete runner; delete agent; return 0; };
27.1.2 装饰模式
(1)装饰模式:对类的功能进行加强
【编程实验】安装喷气装置
//结构型模式大PK——代理模式和装饰模式 //实例:为飞机安装喷气动力装置 #include <iostream> #include <ctime> using namespace std; //飞行接口 class IFly { public: virtual void fly() = 0; virtual ~IFly() {} }; //飞机 class AirPlane : public IFly { public: void fly() { cout << "飞机正在飞行..." << endl; } }; //JetFly class JetFly : public IFly { IFly* airPlane; public: JetFly(IFly* airPlane) { this->airPlane = airPlane; } void speedUp() { cout << "为飞机加装了喷气动力装置,正在加速中..." << endl; } void fly() { speedUp(); airPlane->fly(); } }; int main() { //定义一架飞机 IFly* airPlane = new AirPlane(); //定义装饰类,对功能进行加强 IFly* jet = new JetFly(airPlane); cout << "===增加功能后的飞机" << endl; jet->fly(); delete jet; delete airPlane; return 0; };
27.1.3 最佳实践
(1)装饰类对被装饰的类的行为没有决定权,只有增强作用。而代理可以控制对被代理人的访问。
(2)代理模式是把当前的行为或功能委托给其他对象执行,代理类负责接口限定(如是否可以调用真实角色,一般不对被代理功能当修饰,而是保证原汁原叶的调用。
(3)装饰模式在保证接口不变的情况下加强类的功能,它保证的是被修饰对象功能比原来丰富(当然也可以减弱),但不做准入条件和准入参数的过滤。
27.1.3 最佳实践
(1)装饰类对被装饰的类的行为没有决定权,只有增强作用。而代理可以控制对被代理人的访问。
(2)代理模式是把当前的行为或功能委托给其他对象执行,代理类负责接口限定(如是否可以调用真实角色,一般不对被代理功能当修饰,而是保证原汁原叶的调用。
(3)装饰模式在保证接口不变的情况下加强类的功能,它保证的是被修饰对象功能比原来丰富(当然也可以减弱),但不做准入条件和准入参数的过滤。
27.2 装饰模式 VS 适配器模式
27.2.1 用装饰模式描述丑小鸭
(1)丑小鸭首先是一只天鹅,具备了天鹅所有的行为和属性(即它从天鹅继承而来)
(2)只是小时候,又小、又脏,又不能飞行。随着时间推移,对其属性和行为进行加强,慢慢变成一只白天鹅。
【编程实验】丑小鸭变小天鹅的故事
//结构型模式大PK——装饰模式和适配器模式 //实例:丑小鸭变小天鹅 #include <iostream> #include <ctime> using namespace std; //天鹅接口 class Swan { public: virtual void fly() = 0; //会飞 virtual void cry() = 0; //会叫 virtual void Appearance() = 0; //外观 virtual ~Swan(){} }; //丑小鸭(本质上是天鹅) class UglyDuckling : public Swan { public: //丑小鸭还比较小,不能飞 void fly() { cout << "不能飞" <<endl; } //丑小鸭的叫声 void cry() { cout << "叫声是克噜——克噜——克噜" << endl; } //丑小鸭的外形 void Appearance() { cout << "外形是脏兮兮的白色,毛毛茸茸的大脑袋" <<endl; } }; //装饰类 class Decorator : public Swan { private: Swan* swan; public: Decorator(Swan* swan) { this->swan = swan; } void fly() { swan->fly(); } void cry() { swan->cry(); } void Appearance() { swan->Appearance(); } }; //具体的装饰类(外形美化) class BeautifyAppearance : public Decorator { public: BeautifyAppearance(Swan* swan):Decorator(swan){} //外表美化处理(重写该方法) void Appearance() { //这里是重新实现,不再调用原来的Decorator::desAppearance() cout << "外表是纯白色的,非常惹人喜爱" << endl; } }; //具体装饰类 class StrongBehavior :public Decorator { public: StrongBehavior(Swan* swan):Decorator(swan){} //会飞行了 void fly() { //这里是完全重新实现了被装饰类飞的功能。 cout << "会飞行了!" << endl; } }; int main() { cout <<"===很久很久以前,这里有一只丑陋的小鸭子===" << endl; Swan* duckling = new UglyDuckling(); //展示一下小鸭 duckling->Appearance(); duckling->cry(); duckling->fly(); cout <<"===小鸭子终于发现自己是一只天鹅===" << endl; //首先外形变化 BeautifyAppearance duckling2(duckling); StrongBehavior duckling3(&duckling2); duckling3.Appearance(); duckling3.cry(); duckling3.fly(); delete duckling; return 0; }; /*输出结果: ===很久很久以前,这里有一只丑陋的小鸭子=== 外形是脏兮兮的白色,毛毛茸茸的大脑袋 叫声是克噜——克噜——克噜 不能飞 ===小鸭子终于发现自己是一只天鹅=== 外表是纯白色的,非常惹人喜爱 叫声是克噜——克噜——克噜 会飞行了! */
27.2.2 用适配器模式描述丑小鸭
(1)两个接口:鸭和天鹅。而丑小鸭就相当于适配器。
(2)为了演示适配器的使用,丑小鸭本质上是天鹅,所以应该把鸭子的接口转为天鹅的接口。即鸭子的源接口,目标接口为天鹅。以便让天鹅具备小鸭的一些特点。
【编程实验】一只与众不同的鸭子
//结构型模式大PK——装饰模式和适配器模式 //实例:一只与众不同的鸭子 #include <iostream> #include <ctime> using namespace std; //天鹅接口 class Swan { public: virtual void behavior() = 0; //其他行为,会飞 virtual void cry() = 0; //会叫 virtual void Appearance() = 0; //外观 }; //鸭子的接口 class Duck { public: virtual void behavior() = 0; //会游泳 virtual void cry() = 0; //会叫 virtual void Appearance() = 0; //外观 virtual ~Duck(){} }; //白天鹅 class WhiteSwan : public Swan { public: void cry() { cout << "叫声是克噜——克噜——克噜" << endl; } void Appearance() { cout << "外形是纯白色,惹人喜爱" << endl; } //其他行为 void behavior() { cout << "能够飞行" << endl; } }; //小鸭子 class Duckling : public Duck { public: void cry() { cout << "叫声是嘎——嘎——嘎" << endl; } void Appearance() { cout << "外形是黄白相间,嘴长" << endl; } //描述鸭子的其他行为 void behavior() { cout << "会游泳" << endl; } }; //丑小鸭相当于适配器的角色,丑小鸭本质上是天鹅,所以应该把鸭子 //的接口转为天鹅的接口。即鸭子的源接口,目标接口为天鹅 class UglyDuckling : public WhiteSwan { Duck* duck; //目标接口 public: UglyDuckling(Duck* duck) { this->duck = duck; } //丑小鸭的叫声,直接从父类继承 //丑小鸭的外形,直接从父类继承 //其他行为 void behavior() { //本身会飞 WhiteSwan::behavior(); //学会鸭子的游泳 duck->behavior(); } }; int main() { cout <<"===鸭妈妈有5个孩子,其中4个都是一个模样==="<< endl; Duck* duck = new Duckling(); duck->cry(); duck->Appearance(); duck->behavior(); cout <<"===一只独特的小鸭子,模样是这样的==="<< endl; UglyDuckling uglyDuckling(duck); //丑小鸭 uglyDuckling.cry(); uglyDuckling.Appearance(); uglyDuckling.behavior(); delete duck; return 0; }; /*输出结果: ===鸭妈妈有5个孩子,其中4个都是一个模样=== 叫声是嘎——嘎——嘎 外形是黄白相间,嘴长 会游泳 ===一只独特的小鸭子,模样是这样的=== 叫声是克噜——克噜——克噜 外形是纯白色,惹人喜爱 能够飞行 会游泳 */
27.2.3 最佳实践
(1)装饰模式包装的是自己的兄弟类,隶属于同一家族(相同的父类),而适配器模式则修饰的是非血缘关系类。把一个非本家族伪装成本家族的对象,注意是伪装,因此它的本质还是不同的接口对象。
(2)意图不同
装饰模式的意图是加强对象的功能,而适配器模式关注的是转化,两个对象之间的接口转化。
(3)所作用的对象不同
①装饰模式装饰的对象必须是自己的同宗,也就是相同的父类,只要在具有相同的属性和行为情况下,才能比较行为是增加或减弱。
②适配器模式则必须是两个不对象接口对象,因为它着重于转换
(4)场景不同
①装饰模式只要是想增强功能的,都可以用。
②适配器模式则是一个补救模式,一般出现在系统成熟或己经构建完毕的项目中,作为一个紧急处理手段采用。
(5)扩展性不同
装饰模式容易扩展,如果不需要修饰某对象了,可以随时拿掉,而且装饰类也可以继续扩展。但适配器模式就不同,它在两个不同对象之间架起一座沟通的桥染,建立容易,去掉时需要从系统整体考虑是否能够撤销。