【设计模式学习笔记】代理模式、装饰模式和适配器模式案例详解(C++实现)

简介: 【设计模式学习笔记】代理模式、装饰模式和适配器模式案例详解(C++实现)

一、代理模式

1. 什么是代理模式

Proxy Pattern,代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理来控制对这个对象的访问。所谓的代理,就是指一个具有与被代理对象(代理元)相同接口的类,客户端只有通过Proxy来实现与被代理类的交互,并且在交互过程中 ,代理可以增加其它操作。

代理可以分为多个种类

  • 远程代理:可以隐藏一个对象在不同地址空间的事实,可以理解为将工作委托给远程的代理(服务器)来完成;
  • 虚拟代理:通过代理来存放需要很长时间实例化的对象;
  • 安全代理:用来控制真实对象的访问权限;
  • 智能引用:当调用真实对象时,代理处理另外一些事;

在代理模式中,有四种角色

  • 抽象主题角色subject:真实主题与代理主题的共同接口,并供客户端使用;
  • 真实主题角色RealSubject: 定义了代理角色所代表的真实实体。
  • 代理主题角色Proxy:含有一个引用,使得代理可以访问真实主题角色,并提供一个和抽象主题角色相同的接口,以便于代理角色可以用来替代真是主题角色。代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象,也就是说代理可以执行真是主题角色之外的其他操作。

2. 代理模式的案例

假设现在有一个客户需要买车,他可以去实体店买,也可以在瓜子二手车买,瓜子二手车就是一个代理,它可以销售实体店的车,并提供节假日打折活动。

1. #include <iostream>
2. using namespace std;
3. 
4. //抽象主题角色
5. class CarStore
6. {
7. public:
8.  virtual void sail_Car() = 0;
9. };
10. 
11. //真实主题角色
12. class ReilCarStore : CarStore //实际汽车销售店铺
13. {
14. public:
15.   virtual void sail_Car()
16.   {
17.     cout << "实体店铺直接卖出汽车" << endl;
18.   }
19. };
20. 
21. //代理
22. class GZproxy : public CarStore //瓜子二手车是一个代理商
23. {
24. public:
25.   /*
26.   virtual void sail_Car()
27.   {
28.     cout << "瓜子二手车直营(自己卖)" << endl;
29.   }
30.   */
31.   virtual void sail_Car()
32.   {
33.     ReilCarStore cartore;
34.     cartore.sail_Car(); //表面是瓜子二手车卖车,实际上销售的是实体店的车
35.     discount(); //扩充了实体店卖车的形式和功能
36.   }
37.   void discount()
38.   {
39.     cout << "双11活动打折" << endl;
40.   }
41. };
42. 
43. //客户
44. int main()
45. {
46.   GZproxy dd;
47.   dd.sail_Car();
48. 
49.   system("pause");
50.   return 0;
51. }

二、装饰模式

1. 什么是装饰模式

Decorator Pattern,装饰模式,也叫做包装模式,是结构型模式的一种。装饰模式动态的给一个对象增加了额外的功能,并且这种扩充功能的方式对客户是透明的。装饰模式的具体实现就是把一些功能封装在一个个单独的子类中,并让这些子类包含要被装饰的对象,当有需要功能扩充的时候,客户就可以有选择的通过装饰类来装饰某个对象。装饰模式可以理解为继承的一种替代,他比继承更加灵活,客户可以根据需要自由选择。

  • Component:被装饰的主体,定义了一个对象接口,可以给这些对象增加装饰功能;
  • ConcreteComponent:具体的对象,继承于Component;
  • Decorator:装饰者,继承于Component并从Component类的外部完成对Component类功能的扩充,并且Component类并不需要知道装饰者的存在;

2. 装饰模式案例

假设我们要设计一个游戏角色Hero,它最初只有跑步的技能,但是通过升级可以完成功能扩充,比如飞行,发射激光等。

首先定义一个Component角色,也就是要被装饰的主题的抽象接口。

1. class Hero
2. {
3. public:
4.  virtual void show_skill() = 0;
5. };

然后定义一个具体的要被装饰的对象ConcreteComponent

1. //初始的英雄:只能跑
2. class runHreo : public Hero
3. {
4. public:
5.  void run_skill()
6.  {
7.    cout << "只能跑的超人" << endl;
8.  }
9.  virtual void show_skill()
10.   {
11.     run_skill();
12.   }
13. };

最后添加两个装饰者,每个装饰者都可以完成对被装饰对象不同的功能扩充,一个装饰者可以为英雄角色扩充飞行技能,另一个装饰者可以为英雄角色扩充激光发射功能

1. //超人升级:新增了飞行技能
2. class flyHero : public Hero
3. {
4. private:
5.  Hero* m_hero;
6. public:
7.  flyHero(Hero* hero)
8.  {
9.    this->m_hero = hero;
10.   }
11.   void fly_skill()
12.   {
13.     cout << "拥有飞行技能" << endl;
14.   }
15.   virtual void show_skill()
16.   {
17.     this->m_hero->show_skill();
18.     fly_skill();
19.   }
20. };
21. 
22. //超人升级:可以发射激光
23. class laserHero : public Hero
24. {
25. private:
26.   Hero* m_hero;
27. public:
28.   laserHero(Hero* hero)
29.   {
30.     this->m_hero = hero;
31.   }
32.   void laser_skill()
33.   {
34.     cout << "可以发射激光" << endl;
35.   }
36.   virtual void show_skill()
37.   {
38.     this->m_hero->show_skill();
39.     laser_skill();
40.   }
41. };

最后是客户需求,首先我们让一个英雄角色从跑步到飞行再到激光发射,一步步的获取技能

1. int main()
2. {
3.  //创建一个超人角色
4.  Hero* myHero1 = NULL;
5. 
6.  cout << "*********第一个英雄*********" << endl;
7.  //初始功能只有跑
8.  cout << "======初始形态======" << endl;
9.  myHero1 = new runHreo;
10.   myHero1->show_skill();
11. 
12.   //功能增强:升级飞行技能
13.   cout << "======第一次升级======" << endl;
14.   Hero* myHero2 = new flyHero(myHero1);
15.   myHero2->show_skill();
16. 
17.   //再次升级:可以放大招
18.   cout << "======第二次升级======" << endl;
19.   Hero* myHero3 = new laserHero(myHero2);
20.   myHero3->show_skill();
21. 
22.   delete myHero1;
23.   delete myHero2;
24.   delete myHero3;
25. 
26.   system("pause");
27.   return 0;
28. }

然后我们在创建一个英雄角色,它可以直接获取激光功能

1. {
2.     cout << "*********第二个英雄*********" << endl;
3.  cout << "======初始形态======" << endl;
4.  myHero1 = new runHreo;
5.  myHero1->show_skill();
6. 
7.  //直接获取激光技能
8.  cout << "======升级======" << endl;
9.  myHero3 = new laserHero(myHero1);
10.   myHero3->show_skill();
11.   //增强功能可以自由组合
12. }

通过这两个英雄角色我们可以看到,客户可以根据需求任意组合对待装饰对象的功能扩充。

三、适配器模式

1. 什么是适配器模式

Adapter Pattern,构造型模式之一,也叫做变压器模式和装饰模式都是一种包装模式(Wrapper),通过适配器模式可以改变现有类的接口形式。适配器模式可以将一个类的接口转换成客户希望的另一种形式的接口,使得原本因接口不兼容而无法工作的类可以一起工作,适用于双方都不适合修改的场景。

  • Target:客户期待的接口,可以是抽象类或者接口;
  • Adapter:适配器,对Target和Adaptee进行适配,通过在内部包装一个Adaptee对象,来把源接口转换成目标接口;
  • Adaptee:适配者,也就是需要被适配的类;

2. 适配器模式案例

假设我们现在只有一个RS232标准的接口,但是客户需求一个TTL标准的接口,这时就可以通过一个适配器把RS232接口适配成TTL电平标准。

1. #include <iostream>
2. using namespace std;
3. 
4. //Target:客户需要一个TTL电平接口
5. class TTL
6. {
7. public:
8.  virtual void get_ttl() = 0;
9. };
10. 
11. //Adaptee:现在只有一个RS232接口
12. class RS232
13. {
14. public:
15.   void get_rs232()
16.   {
17.     cout << "RS232接口" << endl;
18.   }
19. };
20. 
21. //Adapter:适配器
22. class adapter : public TTL
23. {
24. private:
25.   RS232* m_232;
26. public:
27.   adapter(RS232* m_232)
28.   {
29.     this->m_232 = m_232;
30.   }
31.   void adapter232_to_ttl()
32.   {
33.     cout << "适配器:将RS232转换为TTL" << endl;
34.   }
35.   virtual void get_ttl()
36.   {
37.     this->m_232->get_rs232();
38.     adapter232_to_ttl();
39.     cout << "ttl电平接口" << endl;
40.   }
41. };
42. 
43. int main()
44. {
45.   RS232* my232 = NULL;
46. 
47.   adapter* ad = NULL;
48. 
49.   //现有一个RS232电平接口
50.   my232 = new RS232;
51.   //需求是TTL接口,所以创建一个适配器
52.   my232->get_rs232();
53.   cout << "=========" << endl;
54.   ad = new adapter(my232);
55.   ad->get_ttl();
56. 
57.   delete my232;
58.   delete ad;
59. 
60.   system("pause");
61.   return 0;
62. }


相关文章
|
1月前
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
1月前
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
|
1月前
|
编译器 C++
【C++核心】指针和引用案例详解
这篇文章详细讲解了C++中指针和引用的概念、使用场景和操作技巧,包括指针的定义、指针与数组、指针与函数的关系,以及引用的基本使用、注意事项和作为函数参数和返回值的用法。
27 3
|
1月前
|
C++
【C++案例】一个项目掌握C++基础-通讯录管理系统
这篇文章通过一个通讯录管理系统的C++项目案例,详细介绍了如何使用C++实现添加、显示、删除、查找、修改和清空联系人等功能。
33 3
|
1月前
|
JavaScript 前端开发 测试技术
一个google Test文件C++语言案例
这篇文章我们来介绍一下真正的C++语言如何用GTest来实现单元测试。
16 0
|
2月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
2月前
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
28天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
8天前
|
设计模式 Java Kotlin
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin语法,推荐查看“简洁”系列教程。本文重点介绍了构建者模式在Kotlin中的应用与改良,包括如何使用具名可选参数简化复杂对象的创建过程,以及如何在初始化代码块中对参数进行约束和校验。
12 3
|
1月前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式