【设计模式学习笔记】外观模式和享元模式案例详解(C++实现)

简介: 【设计模式学习笔记】外观模式和享元模式案例详解(C++实现)

一、外观模式

1. 什么是外观模式

Facade Pattern,外观模式,结构型设计模式之一。外观模式为一个子系统集合提供了一个一致的简单界面,并且外观包含了对各个子系统的引用,客户端可以通过这个外观来访问各个子系统。

外观模式中的角色:

  • Facade:外观类,作为调用接口,提供所有子系统的一致访问界面;
  • Clients:通过外观角色来访问各个子系统;
  • Subsystem:子系统,实现子系统的功能;

2. 外观模式案例

首先创建子系统集合,假设为电脑系统,定义显示屏子系统、主机子系统、键盘子系统

1. class Screen //子系统1
2. {
3. public:
4.  void get_attr()
5.  {
6.    cout << "显示屏子系统" << endl;
7.  }
8. };
9. 
10. class Host //子系统2
11. {
12. public:
13.   void get_attr()
14.   {
15.     cout << "主机子系统" << endl;
16.   }
17. };
18. 
19. class Keyboard //子系统3
20. {
21. public:
22.   void get_attr()
23.   {
24.     cout << "键盘子系统" << endl;
25.   }
26. };

如果客户不适应外观类,而是直接访问这个子系统,那么操作将会比较繁琐

1. void Func1()
2. {
3.  Screen* mScreen;
4.  Host* mHost;
5.  Keyboard* mKeyboard;
6. 
7.  mScreen = new Screen;
8.  mHost = new Host;
9.  mKeyboard = new Keyboard;
10. 
11.   mScreen->get_attr();
12.   mHost->get_attr();
13.   mKeyboard->get_attr();
14. }

要创建每个子系统对象,并逐个调用其方法来访问子系统。

创建一个外观类,它包含对所有子系统的引用

1. class Facade
2. {
3. private:
4.  Screen* mScreen;
5.  Host* mHost;
6.  Keyboard* mKeyboard;
7. public:
8.  Facade()
9.  {
10.     mScreen = new Screen;
11.     mHost = new Host;
12.     mKeyboard = new Keyboard;
13.   }
14.   ~Facade()
15.   {
16.     if (mScreen != NULL)
17.     {
18.       delete mScreen;
19.     }
20.     if (mHost != NULL)
21.     {
22.       delete mHost;
23.     }
24.     if (mKeyboard != NULL)
25.     {
26.       delete mKeyboard;
27.     }
28.   }
29.   void get_attr()
30.   {
31.     this->mScreen->get_attr();
32.     this->mHost->get_attr();
33.     this->mKeyboard->get_attr();
34.   }
35. };

通过外观来访问所有子系统

1. void Func2()
2. {
3.  Facade* f = new Facade;
4.  f->get_attr();
5.  delete f;
6. }

二、享元模式

1. 什么是享元模式

Flyweight Pattern,享元模式,结构型设计模式。

在面向对象系统的设计和实现中,创建对象是最常见的操作,这里就会有一个问题:如果一个应用程序使用了太多对象,就会造成很大的存储开销。特别是对于大量轻量级(细粒度)的对象,比如在文档编辑器的设计过程中,我们如果为每一个字母创建一个对象的时候可能会因为大量的对象而造成存储开销的浪费,例如一个字母a在文档中出现了10000次,而实际上我们可以让这10000个a共享一个对象,这种情况下,我们可以将对象状态分为内部状态和外部状态。在享元模式中可以共享(不会变化)的状态称为内部状态(Intrinsic State),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),其中外部状态和内部状态是相互独立的,外部状态的变化不会引起内部状态的变化。内部状态直接存储在对象中,而外部状态(字母a的大小、字体)可以在适当时机作为参数传递给对象。享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。

享元模式的角色:

  • Flyweight:抽象享元角色,定义了所有具体享元类的接口,通过这个接口可以传入外部状态并作用于外部状态;
  • FlyweightFactory:享元工厂,创建并管理享元对象;
  • ConcreteFlyweight:可共享的内部状态;
  • UnsharedConcreteFlyweight:可以不共享的享元子类;

2. 享元模式案例

假设一个字符串和一个标志作为一对,可以通过标志来确定字符串,比如只要传入标志1就得到字符串hello,也就是说,通过flag可以确定一个字符串。

 

1. class MyStr
2. {
3. protected:
4.  string str;
5. public:
6.  MyStr(string str)
7.  {
8.    this->str = str;
9.  }
10.   virtual void get_str() = 0;
11. };
12. 
13. class Hello : public MyStr
14. {
15. private:
16.   int id;
17. public:
18.   Hello(string str, int id) : MyStr(str)
19.   {
20.     this->id = id;
21.   }
22.   virtual void get_str()
23.   {
24.     cout << "id: " << id << "  对应的str:  " << str << endl;
25.   }
26. };

创建一个工厂

1. class Factory
2. {
3. private:
4.  map<int, Hello*> m;
5. public:
6.  ~Factory()
7.  {
8.    while (!m.empty())
9.    {
10.       Hello* tmp = NULL;
11.       map<int, Hello*>::iterator it = m.begin();
12.       tmp = it->second;
13.       m.erase(it);
14.       delete tmp;
15.     }
16.   }
17.   Hello* get_str(int id)
18.   {
19.     Hello* mtemp;
20.     map<int, Hello*>::iterator it;
21.     it = m.find(id);
22.     if (it == m.end())
23.     {
24.       string temp;
25.       cout << "该字符串未找到,请输入字符串:";
26.       cin >> temp;
27.       mtemp = new Hello(temp, id);
28.       m.insert(make_pair(id, mtemp));
29.       return mtemp;
30.     }
31.     else
32.     {
33.       return it->second;
34.     }
35.   }
36. };

客户端通过工厂获取享元对象,并传入一个标志

1. int main()
2. {
3.  Hello* h1 = NULL, * h2 = NULL;
4.  Factory* f = NULL;
5. 
6.  f = new Factory;
7. 
8.  h1 = f->get_str(1);
9.  h1->get_str();
10. 
11.   h2 = f->get_str(1);
12.   h2->get_str();
13. 
14.   delete h2;
15.   delete h1;
16.   delete f;
17. 
18.   system("pause");
19.   return 0;
20. }


目录
打赏
0
0
0
0
13
分享
相关文章
「全网最细 + 实战源码案例」设计模式——享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在减少大量相似对象的内存消耗。通过分离对象的内部状态(可共享、不变)和外部状态(依赖环境、变化),它有效减少了内存使用。适用于存在大量相似对象且需节省内存的场景。模式优点包括节省内存和提高性能,但会增加系统复杂性。实现时需将对象成员变量拆分为内在和外在状态,并通过工厂类管理享元对象。
162 92
「全网最细 + 实战源码案例」设计模式——命令模式
命令模式(Command Pattern)是一种行为型设计模式,将请求封装成独立对象,从而解耦请求方与接收方。其核心结构包括:Command(命令接口)、ConcreteCommand(具体命令)、Receiver(接收者)和Invoker(调用者)。通过这种方式,命令的执行、撤销、排队等操作更易扩展和灵活。 适用场景: 1. 参数化对象以操作。 2. 操作放入队列或远程执行。 3. 实现回滚功能。 4. 解耦调用者与接收者。 优点: - 遵循单一职责和开闭原则。 - 支持命令组合和延迟执行。 - 可实现撤销、恢复功能。 缺点: - 增加复杂性和类数量。
50 14
「全网最细 + 实战源码案例」设计模式——命令模式
「全网最细 + 实战源码案例」设计模式——责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许将请求沿着处理者链进行发送。每个处理者可以处理请求或将其传递给下一个处理者,从而实现解耦和灵活性。其结构包括抽象处理者(Handler)、具体处理者(ConcreteHandler)和客户端(Client)。适用于不同方式处理不同种类请求、按顺序执行多个处理者、以及运行时改变处理者及其顺序的场景。典型应用包括日志处理、Java Web过滤器、权限认证等。
52 13
「全网最细 + 实战源码案例」设计模式——责任链模式
「全网最细 + 实战源码案例」设计模式——外观模式
外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂的子系统提供一个统一且简化的接口。通过封装多个子系统的复杂性,外观模式使外部调用更加简单、易用。例如,在智能家居系统中,外观类可以同时控制空调、灯光和电视的开关,而用户只需发出一个指令即可。
143 69
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
51 8
「全网最细 + 实战源码案例」设计模式——策略模式
「全网最细 + 实战源码案例」设计模式——模板方法模式
模板方法模式是一种行为型设计模式,定义了算法的骨架并在父类中实现不变部分,将可变部分延迟到子类实现。通过这种方式,它避免了代码重复,提高了复用性和扩展性。具体步骤由抽象类定义,子类实现特定逻辑。适用于框架设计、工作流和相似算法结构的场景。优点包括代码复用和符合开闭原则,缺点是可能违反里氏替换原则且灵活性较低。
62 7
「全网最细 + 实战源码案例」设计模式——模板方法模式
|
29天前
|
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
88 40
「全网最细 + 实战源码案例」设计模式——适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,通过引入适配器类将一个类的接口转换为客户端期望的另一个接口,使原本因接口不兼容而无法协作的类能够协同工作。适配器模式分为类适配器和对象适配器两种,前者通过多重继承实现,后者通过组合方式实现,更常用。该模式适用于遗留系统改造、接口转换和第三方库集成等场景,能提高代码复用性和灵活性,但也可能增加代码复杂性和性能开销。
71 28
「全网最细 + 实战源码案例」设计模式——组合模式
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。它允许客户端以一致的方式对待单个对象和对象集合,简化了复杂结构的处理。组合模式包含三个主要组件:抽象组件(Component)、叶子节点(Leaf)和组合节点(Composite)。通过这种模式,客户端可以统一处理简单元素和复杂元素,而无需关心其内部结构。适用于需要实现树状对象结构或希望以相同方式处理简单和复杂元素的场景。优点包括支持树形结构、透明性和遵循开闭原则;缺点是可能引入不必要的复杂性和过度抽象。
76 22
「全网最细 + 实战源码案例」设计模式——代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,通过代理对象控制对目标对象的访问并添加额外功能。它分为静态代理和动态代理,后者包括JDK动态代理和CGLIB动态代理。JDK动态代理基于接口反射生成代理类,而CGLIB通过继承目标类生成子类。代理模式适用于延迟初始化、访问控制、远程服务、日志记录和缓存等场景,优点是职责分离、符合开闭原则和提高安全性,缺点是增加系统复杂性。
74 25