一、享元模式是什么?
享元模式是一种结构型的软件设计模式,通过共享对象的方式,尽可能减少内存占用,从而达到优化的目的。
就像打麻将,同时有10桌在玩,每桌都有4个"八筒",如果建立40个"八筒"对象,那就非常冗余,但如果用享元模式建立一套麻将牌,每桌打出"八筒"时,就调用享元中的"八筒",相当于只用了1个对象,这样即节省了资源,也完成了需求。
上述例子中,桌号和牌号就是享元模式的外蕴状态,如A1八筒,就是A桌的第一个"八筒",A和1是外蕴状态;而卡牌"八筒"本身就是内蕴状态,内蕴是可以共享的。外蕴随环境变化,占用资源也少的多,往往只是简单的数据结构。
享元模式的优点:
- 减少资源浪费。共享资源极大程度降低了系统的资源消耗。
- 提高系统运行效率。当资源过度使用时,系统效率会大受影响。
享元模式的缺点:
- 维护共享对象,需要额外开销。
- 系统复杂度提高。运行享元,除了内外状态,还有线程方面都要充分考虑。
二、享元模式
2.1 结构图
客户端即Main主函数,调用享元工厂获取享元对象。
2.2 代码示例
场景描述:模拟组合一套八卦牌。
//Flyweight.h /****************************************************/ #pragma once #include <iostream> #include <unordered_map> #include <vector> #include <list> using namespace std; // 抽象享元 class Flyweight { public: // 操作 virtual void operation() = 0; }; // 具体享元 class ConcreteFlyweight : public Flyweight { public: // 构造函数 ConcreteFlyweight(string name) : m_name(name) {} // 操作 virtual void operation() { cout << "打出" << m_name << endl; } private: string m_name; }; // 享元工厂 class FlyweightFactory { public: // 析构函数 ~FlyweightFactory() { for (auto it : flyweights) { cout << "销毁" << it.first << "牌" << endl; delete it.second; it.second = nullptr; } flyweights.clear(); } // 获取享元 Flyweight* getFlyweight(string name) { // 若没有,则创建 if (flyweights.find(name) == flyweights.end()) { cout << "创建" << name << "牌" << endl; flyweights[name] = new ConcreteFlyweight(name); } else { cout << "已有" << name << "牌" << endl; } return flyweights[name]; } private: std::unordered_map<string, Flyweight*> flyweights; };
//main.cpp /****************************************************/ #include <iostream> #include <string> #include "Flyweight.h" using namespace std; int main() { FlyweightFactory *factory = new FlyweightFactory(); Flyweight* f1 = factory->getFlyweight("乾"); Flyweight* f2 = factory->getFlyweight("坤"); Flyweight* f3 = factory->getFlyweight("坎"); Flyweight* f4 = factory->getFlyweight("离"); Flyweight* f5 = factory->getFlyweight("震"); Flyweight* f6 = factory->getFlyweight("巽"); Flyweight* f7 = factory->getFlyweight("艮"); Flyweight* f8 = factory->getFlyweight("兑"); Flyweight* f9 = factory->getFlyweight("坤"); f3->operation(); delete factory; factory = nullptr; return 0; }
程序结果如下。
八卦的八个牌在初次调用时因为不存在所以创建,而第九次调用已有的坤,便不用new了。删除工厂后,析构函数别忘了将new的数据delete。
三、总结
我尽可能用较通俗的话语和直观的代码例程,来表述我对享元模式的理解,或许有考虑不周到的地方,如果你有不同看法欢迎评论区交流!希望我举的例子能帮助你更好地理解享元模式。
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!