【设计模式学习笔记】代理模式、装饰模式和适配器模式案例详解(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. }


相关文章
|
4月前
|
设计模式 Java 数据库连接
【设计模式】【结构型模式】代理模式(Proxy)
一、入门 什么是代理模式? 代理模式(Proxy Pattern)是一种结构型设计模式,允许你提供一个代理对象来控制对另一个对象的访问。 代理对象在客户端和目标对象之间起到中介作用,可以在不改变目标对
105 10
|
8月前
|
设计模式 缓存 Java
「全网最细 + 实战源码案例」设计模式——代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,通过代理对象控制对目标对象的访问并添加额外功能。它分为静态代理和动态代理,后者包括JDK动态代理和CGLIB动态代理。JDK动态代理基于接口反射生成代理类,而CGLIB通过继承目标类生成子类。代理模式适用于延迟初始化、访问控制、远程服务、日志记录和缓存等场景,优点是职责分离、符合开闭原则和提高安全性,缺点是增加系统复杂性。
198 25
|
9月前
|
设计模式 前端开发 数据安全/隐私保护
前端必须掌握的设计模式——代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,通过引入“替身”对象来间接访问真实对象,从而解耦并提升性能和安全性。例如,知名艺人复出后,经纪人作为代理筛选商单,确保只处理符合团队利益的请求。代码实现中,定义接口`IService`,艺人和经纪人都实现该接口,经纪人在访问时进行过滤和转发。代理模式常用于权限控制、性能优化等场景,如前端中的Tree-shaking和ES6的Proxy构造方法。
前端必须掌握的设计模式——代理模式
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
12月前
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
7月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
3月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
85 0
|
3月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
166 0