flyweight模式
参考资料
• 维基百科:https://en.wikipedia.org/wiki/Flyweight_pattern
Flyweight模式简介
GoF:Use sharing to support large numbers of fine-grained objects efficiently.
GoF:使用共享的方式来高效地支持大量细粒度对象的使用。
Wikipedia:In computer programming, flyweight is a software design pattern. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory. Often some parts of the object state can be shared, and it is common practice to hold them in external data structures and pass them to the flyweight objects temporarily when they are used.
Wikipedia:在计算机编程中,享元是一种软件设计模式。一个享元是一个对象,该对象通过和其他相似对象共享尽可能多的数据来减少内存的使用。当对象的重复使用将导致令人无法接受的内存使用量时,享元模式是一种解决大量使用对象问题的方法。通常情况下,对象的部分状态是可以共享的,通常我们将这部分数据存储在外部的数据结构中,当需要使用时,再将它们临时性地传递给享元。
百度百科:享元模式(FlyWeight),运用共享技术有效的支持大量细粒度的对象。
Flyweight模式详解
• 设计意图
运用共享技术来有效地支持大量细粒度的对象使用。
• 结构图
• 结构说明
▶ Flyweight
抽象享元角色,为具体享元角色定义了接口,通过接口享元可以接收外部状态。
▶ ConcreteFlyweight
具体享元角色,实现抽象享元角色定义的接口。如果存在内部状态,则为内部状态提供存储空间。一个具体享元角色必须是可以共享的,它存储的任何状态都必须内蕴,这就是说状态必须与具体享元角色对象的上下文无关。
▶ UnsharedConcreteFlyweight
复合享元角色。实际情况中,并不是所有的享元子类型都需要被共享。抽象享元角色接口只是使共享行为可行,但并不强制要进行共享。这种情况十分常见:在某些享元对象结构层次中,复合享元对象将具体享元对象作为孩子。
▶ FlyweightFactory
享元工厂角色,创建并管理享元对象实体。享元工厂将确保享元能够被正确地共享。当客户端请求一个享元,享元工厂对象将提供一个已有的享元实例,如果不存在,则创建一个新的享元实体。
▶ Client
客户端角色。维护享元对象的引用,计算或存储享元对象的外部状态。
• 享元共享示意图
Facade模式举例
• 例子一
这个例子出自于Wikipedia:https://en.wikipedia.org/wiki/Flyweight_pattern
#include <map> #include <list> #include <string> #include <sstream> #include <iomanip> #include <iostream> using namespace std; // Instances of CoffeeFlavour will be the Flyweights. class CoffeeFlavour { private: string m_strFlavourName; public: CoffeeFlavour(const string &strFlavourName = "Unknown") : m_strFlavourName(strFlavourName) {} public: const char *GetFlavourName() const { return m_strFlavourName.c_str(); } }; typedef const CoffeeFlavour * const CPCCoffeeFlavour; // Menu acts as a FlyweightFactory and cache for CoffeeFlavour Flyweight objects class Menu { typedef map<string, CPCCoffeeFlavour> FlavoursMap; typedef map<string, CPCCoffeeFlavour>::iterator FlavoursMapIterator; public: ~Menu() { FlavoursMapIterator it = m_FlavoursMap.begin(); for (; m_FlavoursMap.end() != it; it++) { CPCCoffeeFlavour cpcCoffeeFlavour = it->second; if (cpcCoffeeFlavour) { delete cpcCoffeeFlavour; } } m_FlavoursMap.clear(); } private: FlavoursMap m_FlavoursMap; public: CPCCoffeeFlavour LookUp(const string &strFlavourName) { FlavoursMapIterator it = m_FlavoursMap.find(strFlavourName); if (m_FlavoursMap.end() == it) { m_FlavoursMap.insert( pair<string, CPCCoffeeFlavour>(strFlavourName, ::new CoffeeFlavour(strFlavourName)) ); } return m_FlavoursMap[strFlavourName]; } int GetCoffeeFlavourCount() { return m_FlavoursMap.size(); } }; class Order { private: int m_nTableNumber; CPCCoffeeFlavour m_cpcCoffeeFlavour; public: Order(int nTableNumber, CPCCoffeeFlavour cpcCoffeeFlavour) : m_nTableNumber(nTableNumber), m_cpcCoffeeFlavour(cpcCoffeeFlavour) {} public: void Serve() { cout << left; cout << "Serving " << setw(10) << m_cpcCoffeeFlavour->GetFlavourName() << " to table " << setw(3) << m_nTableNumber << endl; } }; class CoffeeShop { private: Menu m_CoffeeMenu; list<Order> m_CoffeeOrders; public: void TakeOrder(const string &strFlavourName, int nTableNumber) { CPCCoffeeFlavour cpcFlavour = m_CoffeeMenu.LookUp(strFlavourName); m_CoffeeOrders.push_back(Order(nTableNumber, cpcFlavour)); } void Service() { list<Order>::iterator it = m_CoffeeOrders.begin(); for (; m_CoffeeOrders.end() != it; it++) { it->Serve(); } } string Report() { stringstream ss; ss << "Total CoffeeFlavour Objects Made: " << m_CoffeeMenu.GetCoffeeFlavourCount(); return ss.str(); } }; int main() { CoffeeShop shop; shop.TakeOrder("Cappuccino", 2 ); shop.TakeOrder("Frappe", 1 ); shop.TakeOrder("Espresso", 1 ); shop.TakeOrder("Frappe", 897); shop.TakeOrder("Cappuccino", 97 ); shop.TakeOrder("Frappe", 3 ); shop.TakeOrder("Espresso", 3 ); shop.TakeOrder("Cappuccino", 3 ); shop.TakeOrder("Espresso", 96 ); shop.TakeOrder("Frappe", 552); shop.TakeOrder("Cappuccino", 121); shop.TakeOrder("Espresso", 121); shop.Service(); cout << shop.Report() << endl; return 1; }
CoffeeFlavour作为享元共享结构图如下: