前言
尊重原创,本系列文本解析部分主要基于Candidate for Master’s Degree School of Computer Wuhan University的K_Eckel([email protected] )《设计模式精解-GoF 23 种设计模式解析附 C++实现源码》。为了避免重造轮子,本系列博文对源码在ubuntu16.04下做了验证并上传到了gitee ,再次感谢。
如有问题,可邮件联系我([email protected] )并共同探讨解决方案。
目录
创建型模式(Creating Pattern)
Factory 模式 | AbstactFactory 模式 | Singleton 模式 | Builder 模式 | Prototype 模式
结构型模式(Structrual Pattern)
Bridge 模式 | Adapter 模式 | Decorator 模式 | Composite 模式 | Flyweight 模式 | Facade 模式 | Proxy 模式
行为型模式(Behavioral Pattern)
Template 模式 | Strategy 模式 | State 模式 | Observer 模式 | Memento 模式 | Mediator 模式 | Command 模式 | Visitor 模式 | Iterator 模式 | Interpreter 模式 | Chain of Responsibility 模式
Flyweight 模式简介:
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。
问题
在面向对象系统的设计何实现中,创建对象是最为常见的操作。这里面就有一个问题:
如果一个应用程序使用了太多的对象, 就会造成很大的存储开销。 特别是对于大量轻量级(细粒度)的对象,比如在文档编辑器的设计过程中,我们如果为没有字母创建一个对象的话,系统可能会因为大量的对象而造成存储开销的浪费。例如一个字母“a
”在文档中出现了100000
次, 而实际上我们可以让这一万个字母“a
” 共享一个对象, 当然因为在不同的位置,可能字母“ a” 有不同的显示效果(例如字体和大小等设置不同), 在这种情况我们可以为将对象的状态分为“外部状态”和“ 内部状态”, 将可以被共享(不会变化)的状态作为内部状态存储在对象中, 而外部对象(例如上面提到的字体、 大小等) 我们可以在适当的时候将外部对象最为参数传递给对象(例如在显示的时候,将字体、大小等信息传递给对象)。
模式选择
上面解决问题的方式被称作 Flyweight 模式解决上面的问题,其典型的结构图为:
图 1:Flyweight Pattern 结构图
实现
完整代码示例( code)
Flyweight 模式完整的实现代码(所有代码采用 C++实现,并在 Visual Studio Code,Version: 1.36.1 下测试运行)。
源码gitee地址:点击这里
代码目录结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\structuralPattern\Flyweight> tree /F 卷 Windows 的文件夹 PATH 列表 卷序列号为 F0C5-AFA6 C:. ├─include │ Flyweight.h │ FlyweightFactory.h │ └─src a.out Flyweight.cpp FlyweightFactory.cpp main.cpp PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\structuralPattern\Flyweight>
Flyweight.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // Flyweight.h #ifndef _FLYWEIGHT_H_ #define _FLYWEIGHT_H_ #include <string> using namespace std; class Flyweight { private: string _intrinsicState; protected: Flyweight(string intrinsicState); public: Flyweight(/* args */); virtual ~Flyweight(); virtual void Operation(const string& extrinsicState); string GetIntrinsicState(); }; class ConcreteFlyweight : public Flyweight { private: /* data */ public: ConcreteFlyweight(string intrinsicState); ~ConcreteFlyweight(); virtual void Operation(const string& extrinsicState); }; #endif //~_FLYWEIGHT_H_
FlyweightFactory.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // FlyweightFactory.h #ifndef _FLYWEIGHTFACTORY_H_ #define _FLYWEIGHTFACTORY_H_ #include <string> #include <vector> #include "Flyweight.h" using namespace std; class FlyweightFactory { private: vector<Flyweight*> _fly; public: FlyweightFactory(/* args */); ~FlyweightFactory(); Flyweight* GetFlyweight(const string& key); }; #endif //~_FLYWEIGHTFACTORY_H_
Flyweight.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // Flyweight.cpp #include "../include/Flyweight.h" #include <iostream> using namespace std; Flyweight::Flyweight(string intrinsicState) { this->_intrinsicState = intrinsicState; } Flyweight::~Flyweight() {} void Flyweight::Operation(const string& extrinsicState) {} string Flyweight::GetIntrinsicState() { return this->_intrinsicState; } ConcreteFlyweight::ConcreteFlyweight(string intrinsicState) : Flyweight(intrinsicState) { cout<<"ConcreteFlyweight Build....."<<intrinsicState<<endl; } ConcreteFlyweight::~ConcreteFlyweight() {} void ConcreteFlyweight::Operation(const string& extrinsicState) { cout << "ConcreteFlyweight: 内 蕴[" << this->GetIntrinsicState() << "] 外 蕴[" << extrinsicState << "]" << endl; }
FlyweightFactory.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // FlyweightFactory.cpp #include "../include/FlyweightFactory.h" #include <cassert> #include <iostream> #include <string> using namespace std; FlyweightFactory::FlyweightFactory(/* args */) {} FlyweightFactory::~FlyweightFactory() {} Flyweight* FlyweightFactory::GetFlyweight(const string& key) { vector<Flyweight*>::iterator it = _fly.begin(); for (; it != _fly.end(); it++) { //找到了,就一起用,^_^ if ((*it)->GetIntrinsicState() == key) { printf("already created by users... \n"); return *it; } } Flyweight* fn = new ConcreteFlyweight(key); _fly.push_back(fn); return fn; }
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // main.cpp #include <iostream> #include "../include/Flyweight.h" #include "../include/FlyweightFactory.h" using namespace std; int main(int argc, char* argv[]) { FlyweightFactory* fc = new FlyweightFactory(); Flyweight* fw1 = fc->GetFlyweight("hello"); Flyweight* fw2 = fc->GetFlyweight("world!"); Flyweight* fw3 = fc->GetFlyweight("hello"); return 0; }
代码说明
Flyweight
模式在实现过程中主要是要为共享对象提供一个存放的“仓库”(对象池),这里是通过 C++ STL 中 Vector
容器, 当然就牵涉到 STL 编程的一些问题( Iterator
使用等)。
另外应该注意的就是对对象“仓库”(对象池) 的管理策略(查找、 插入等), 这里是通过直接的顺序遍历实现的,当然我们可以使用其他更加有效的索引策略,例如 Hash 表的管理策略,当时这些细节已经不是 Flyweight
模式本身要处理的了。
编译运行结果:
1 2 3 4 5 6 PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\structuralPattern\Flyweight\src> g++ *.cpp -std=c++11 PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\structuralPattern\Flyweight\src> .\a.exe ConcreteFlyweight Build.....hello ConcreteFlyweight Build.....world! already created by users... PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\structuralPattern\Flyweight\src>
讨论
我们在 State
模式和 Strategy
模式中会产生很多的对象,因此我们可以通过 Flyweight
模式来解决这个问题。