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


相关文章
|
6天前
|
设计模式 缓存 应用服务中间件
「全网最细 + 实战源码案例」设计模式——外观模式
外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂的子系统提供一个统一且简化的接口。通过封装多个子系统的复杂性,外观模式使外部调用更加简单、易用。例如,在智能家居系统中,外观类可以同时控制空调、灯光和电视的开关,而用户只需发出一个指令即可。
109 69
|
4月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
20天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
27天前
|
设计模式 JSON 前端开发
前端必须掌握的设计模式——适配器模式
适配器模式是一种结构型设计模式,用于使接口不兼容的对象能够相互合作。通过在客户端和系统之间引入一个“中间层”适配器,将不同类型的输入数据转换为系统能处理的标准格式,减轻系统的负担,提高扩展性和可维护性。例如,MacBook的扩展坞将多种接口(如HDMI、USB)转换为Type-C接口,实现多接口兼容。
|
4月前
|
设计模式 Java 程序员
Java设计模式-适配器模式(8)
Java设计模式-适配器模式(8)
|
3月前
|
设计模式 Java
Java设计模式之适配器模式
这篇文章详细讲解了Java设计模式中的适配器模式,包括其应用场景、实现方式及代码示例。
67 0
|
4月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
5月前
|
设计模式 XML 存储
【六】设计模式~~~结构型模式~~~适配器模式(Java)
文章详细介绍了适配器模式(Adapter Pattern),这是一种结构型设计模式,用于将一个类的接口转换成客户期望的另一个接口,使原本不兼容的接口能够一起工作,提高了类的复用性和系统的灵活性。通过对象适配器和类适配器两种实现方式,展示了适配器模式的代码应用,并讨论了其优点、缺点以及适用场景。
|
5月前
|
设计模式 Java
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
文章提供了一份常用设计模式的全面介绍,包括创建型模式、结构型模式和行为型模式。每种设计模式都有详细的概念讲解、案例说明、代码实例以及运行截图。作者通过这些模式的介绍,旨在帮助读者更好地理解源码、编写更优雅的代码,并进行系统重构。同时,文章还提供了GitHub上的源码地址,方便读者直接访问和学习。
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
|
6月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
52 3