C++设计模式---享元模式----浪费可耻,节俭光荣

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介:

概述

一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。

想想我们编辑文档用的word,文档里文字很多都是重复的,我们不可能为每一个出现的汉字都创建独立的空间,这样代价太大,那么我们如何去避免系统中出现大量相同或相似的对象,同时又不影响客户端程序通过面向对象的方式对这些对象进行操作?

享元模式正为解决这一类问题而诞生。享元模式通过共享技术实现相同或相似对象的重用,在逻辑上每一个出现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,这个对象可以出现在一个字符串的不同地方,相同的字符对象都指向同一个实例,在享元模式中,存储这些共享实例对象的地方称为享元池(Flyweight Pool)。我们可以针对每一个不同的字符创建一个享元对象,将其放在享元池中,需要时再从享元池取出。

实现策略

作用:运用共享技术有效地支持大量细粒度的对象。

内部状态intrinsic和外部状态extrinsic:

1)Flyweight模式中,最重要的是将对象分解成intrinsic和extrinsic两部分。
2)内部状态:在享元对象内部并且不会随环境改变而改变的共享部分,可以称为是享元对象的内部状态
3)外部状态:而随环境改变而改变的,取决于应用环境,或是实时数据,这些不可以共享的东西就是外部状态了。
4)内部状态和外部状态之间的区别:
在Flyweight模式应用中,通常修改的是外部状态属性,而内部状态属性一般都是用于参考或计算时引用。
Flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部状态则由Client对象存储或计算。当用户调用Flyweight对象的操作时,将该状态传递给它。

以文字处理软件为例:
内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。如字符代码,字符大小……
外部状态取决于flyweight场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight,如字符位置,字符颜色……

组成

①Flyweight:

享元类的基类,定义一个接口,通过这个接口Flyweight可以接受并作用于外部状态。

②ConcreteFlyweight:

实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的(intrinsic);即,它必须独立于ConcreteFlyweight对象的场景。

③UnsharedConcreteFlyweight:

并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,④UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。

FlyweightFactory:

1) 创建并管理Flyweight对象。
2)确保合理地共享Flyweight。当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)

⑥Client

1)维持一个对Flyweight的引用。
2)计算或存储一个(多个)Flyweight的外部状态。

UML



示例代码
// Flyweight.h
  1. // Flyweight.h  
  2. #ifndef _FLYWEIGHT_H_  
  3. #define _FLYWEIGHT_H_  
  4.   
  5. #include <string>  
  6. #include <vector>  
  7.   
  8. using namespace std;  
  9.   
  10. //基类,定义操作接口Operation  
  11. class Flyweight  
  12. {  
  13. public:  
  14.     //操作外部状态extrinsicState  
  15.     virtual void Operation(const string& extrinsicState) = 0;  
  16.     string GetIntrinsicState( );  
  17.     virtual ~Flyweight( );  
  18. protected:  
  19.     Flyweight(string intrinsicState);  
  20. private:  
  21.       
  22.     // 内部状态,也可以放在ConcreteFlyweight中  
  23.     string _intrinsicState;  
  24. };  
  25.   
  26.   
  27. /* 
  28. ConcreteFlyweight:实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。 
  29. ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的(intrinsic); 
  30. 即,它必须独立于ConcreteFlyweight对象的场景。 
  31. */  
  32. class ConcreteFlyweight : public Flyweight  
  33. {  
  34. public:  
  35.     //实现接口函数  
  36.     virtual void Operation(const string& extrinsicState);  
  37.     ConcreteFlyweight(string intrinsicState);  
  38.     ~ConcreteFlyweight();  
  39. };  
  40.   
  41.   
  42. /* 
  43. UnsharedConcreteFlyweight:并非所有的Flyweight子类都需要被共享。 
  44. Flyweight接口使共享成为可能,但它并不强制共享。 
  45. 在Flyweight对象结构的某些层次, 
  46. UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。 
  47. */  
  48. class UnsharedConcreteFlyweight:public Flyweight  
  49. {  
  50. public:  
  51.     virtual void Operation(const string& extrinsicState);  
  52.     UnsharedConcreteFlyweight(string intrinsicState);  
  53.     ~UnsharedConcreteFlyweight();  
  54. };  
  55.   
  56. class FlyweightFactory  
  57. {  
  58. public:  
  59.     FlyweightFactory();  
  60.     ~FlyweightFactory();  
  61.     //获得一个请求的Flyweight对象  
  62.     Flyweight* GetFlyweight(string key);  
  63.     //获取容器中存储的对象数量  
  64.     void GetFlyweightCount();  
  65. protected:  
  66. private:  
  67.     //保存内部状态对象的容器  
  68.     vector<Flyweight*> m_vecFly;  
  69. };  
  70. #endif  

// Flyweight.cpp
  1. // Flyweight.cpp  
  2. #include "Flyweight.h"  
  3. #include <iostream>  
  4.   
  5. using namespace std;  
  6.   
  7. Flyweight::Flyweight(string intrinsicState)  
  8. {  
  9.     this->_intrinsicState = intrinsicState;  
  10. }  
  11.   
  12. Flyweight::~Flyweight()  
  13. {}  
  14.   
  15. string Flyweight::GetIntrinsicState()  
  16. {  
  17.     return this->_intrinsicState;  
  18. }  
  19.   
  20. ConcreteFlyweight::ConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)  
  21. {  
  22. }  
  23.   
  24. ConcreteFlyweight::~ConcreteFlyweight()  
  25. {  
  26. }  
  27.   
  28. void ConcreteFlyweight::Operation(const string& extrinsicState)  
  29. {  
  30.     cout << this->GetIntrinsicState() << endl;  
  31.     cout << extrinsicState << endl;  
  32. }  
  33.   
  34. UnsharedConcreteFlyweight::UnsharedConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)  
  35. {  
  36. }  
  37.   
  38. UnsharedConcreteFlyweight::~UnsharedConcreteFlyweight()  
  39. {  
  40. }  
  41.   
  42. void UnsharedConcreteFlyweight::Operation(const string& extrinsicState)  
  43. {  
  44.     cout << "extrinsicState" << endl;  
  45. }  
  46.   
  47. FlyweightFactory::FlyweightFactory()  
  48. {}  
  49.   
  50. FlyweightFactory::~FlyweightFactory()  
  51. {}  
  52.   
  53. //若该对象已存在,直接返回,否则新建一个对象,存入容器中,再返回  
  54. Flyweight* FlyweightFactory::GetFlyweight(string key)  
  55. {  
  56.     vector<Flyweight*>::iterator iter = this->m_vecFly.begin();  
  57.     for(;iter!= this->m_vecFly.end();iter++)  
  58.     {  
  59.         if((*iter)->GetIntrinsicState() == key)  
  60.         {  
  61.             return *iter;  
  62.         }  
  63.     }  
  64.     Flyweight* fly = new ConcreteFlyweight(key);  
  65.     this->m_vecFly.push_back(fly);  
  66.     return fly;  
  67. }  
  68.   
  69. void FlyweightFactory::GetFlyweightCount()  
  70. {  
  71.     cout << this->m_vecFly.size() << endl;  
  72. }  

main.cpp
  1. #include "Flyweight.h"  
  2. #include <iostream>  
  3. #include <string>  
  4.   
  5. using namespace std;  
  6.   
  7. int main()  
  8. {  
  9.     //外部状态extrinsicState  
  10.     string extrinsicState = "ext";  
  11.   
  12.     //工厂对象,工厂对象  
  13.     FlyweightFactory* fc = new FlyweightFactory();  
  14.   
  15.     //向工厂申请一个Flyweight对象,且该对象的内部状态值为“hello”  
  16.     Flyweight* fly = fc->GetFlyweight("hello");  
  17.   
  18.     Flyweight* fly1 = fc->GetFlyweight("hello");  
  19.   
  20.     //应用外部状态  
  21.     fly->Operation(extrinsicState);  
  22.   
  23.     fc->GetFlyweightCount();  
  24.   
  25.     return 0;  
  26. }  

Makefile
  1. CC = gcc  
  2. CXX = g++  
  3.   
  4. OBJECT = Flyweight.o main.o  
  5. TARGET = Flyweight.exe  
  6. INC = -I./  
  7.   
  8.   
  9. $(TARGET) : $(OBJECT)  
  10.     $(CXX) $(OBJECT) -o $(TARGET)  
  11.   
  12. %.o : %.cpp  
  13.     $(CXX) -c $< -o $@ $(INC)  
  14.   
  15.   
  16. .PHONY : clean  
  17. clean :  
  18.     del $(OBJECT) $(TARGET)  
  19.     rm -rf $(OBJECT) $(TARGET)  


参考:
另外一个围棋的例子:

转载:http://blog.csdn.net/gatieme/article/details/24925741
相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
2月前
|
设计模式 Java
Java设计模式-享元模式(12)
Java设计模式-享元模式(12)
|
3月前
|
设计模式 存储 Java
【十】设计模式~~~结构型模式~~~享元模式(Java)
文章详细介绍了享元模式(Flyweight Pattern),这是一种对象结构型模式,通过共享技术实现大量细粒度对象的重用,区分内部状态和外部状态来减少内存中对象的数量,提高系统性能。通过围棋棋子的设计案例,展示了享元模式的动机、定义、结构、优点、缺点以及适用场景,并探讨了单纯享元模式和复合享元模式以及与其他模式的联用。
【十】设计模式~~~结构型模式~~~享元模式(Java)
|
4月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
42 3
|
4月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
53 2
|
4月前
|
设计模式 存储 JavaScript
js设计模式【详解】—— 享元模式
js设计模式【详解】—— 享元模式
64 6
|
5月前
|
设计模式 缓存 Java
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
|
5月前
|
设计模式 存储 Java
Java设计模式之享元模式详解
Java设计模式之享元模式详解
|
6月前
|
设计模式 开发框架 算法
C++中的设计模式:基本概念与应用
C++中的设计模式:基本概念与应用
60 2
|
5月前
|
设计模式
享元模式-大话设计模式
享元模式-大话设计模式
|
6月前
|
设计模式 Java 开发者
【搞懂设计模式】享元模式:共享节约,皆大欢喜!
【搞懂设计模式】享元模式:共享节约,皆大欢喜!
101 0