思考享元模式
①享元模式的本质:分离与共享。享元模式的关键在于分离变与不变,把不变部分作为享元对象的内部状态,而变化部分则作为外部状态,由外部来维护.这样享元对象就能够被共享,从而减少对象的数量,并节省大量的内存空间。
②享元模式的变与不变:为什么在一个地方要预留接口,一个常见的原因是这里存在变化,可能在今后需要扩展或改变己有的实现,而预留接口作为“可插入性的保证”
③享元对象:又有共享(ConcreteFlyweight)与不共享(UnsharedConcreteFlyweight)之分。不共享一般出现在和组合模式合用的情况,通常共享是叶子对象,一般不共享的部分是由共享部分组合而成,由于所有细粒度的叶子对象己经缓存了,那么缓存组合对象就没有什么意义。(如权限管理中某安全实体的“查看”和“修改”是可共享的,如果将“查看”和“修改”组合成“操作”权限的话,则“操作”权限是不用缓存(共享)的,因为己经在细粒度上进行了缓存)。(见后面的例子)
【编程实验】围棋软件设计
①内部状态:每个围棋那么多的棋子,可设置为享元对象,有如下属性颜色、大小、形状。
②外部状态:棋子在棋盘中的位置。这是不可共享的。
//声明文件
//结构型模式:享元模式 //场景:围棋软件设计。 //内部状态——围棋棋子数量多,但分只为两类:白棋和黑棋。 // 有颜色、大小、形态等属性,是可共享的对象。 //外部状态——棋子在棋盘中的位置。 #include <iostream> #include <string> #include <map> using namespace std; //************************************享元类************************** //非享元对象:UnsharedConcreteFlyweight(外部状态) class CPos{ private: int X; int Y; public: CPos(int x, int y); void SetX(int x); int GetX(); void SetY(int y); int GetY(); }; //享元抽象类 class CWeight{ protected: string strColor; public: virtual ~CWeight(); void SetColor(string color); string GetColor(); //显示棋子在棋盘中的位置 //可以通过这个接口,将外部状态传入享元对象中 virtual void Disp(CPos& pos) = 0; }; //享元对象:ConcreteFlyweight(内部状态) class CFly : public CWeight{ public: CFly(string color); ~CFly(); void Disp(CPos& pos); }; //************************************享元工厂类************************** class CChessFac{ private: static map<string, CWeight*> mpChess; public: static CWeight* GetChess(string color); static void RemoveAll(); };
//实现文件
//************************************享元类************************** //非享元对象:UnsharedConcreteFlyweight(外部状态) CPos::CPos(int x, int y){X = x; Y = y;} void CPos::SetX(int x){ X = x;} int CPos::GetX(){return X;} void CPos::SetY(int y){Y = y;} int CPos::GetY(){return Y;} //享元抽象类 CWeight::~CWeight(){cout << "~CWeight" << endl;} void CWeight::SetColor(string color){strColor = color;} string CWeight::GetColor(){return strColor;} //享元对象:ConcreteFlyweight(内部状态) CFly::CFly(string color){SetColor(color);} CFly::~CFly(){cout << "~CFly" << endl; } void CFly::Disp(CPos& pos) { cout << "********************************************" << endl; cout << "Chess's Color : " << strColor << endl; cout << "Chess's Pos : (" << pos.GetX() << ", " << pos.GetY() << ")" << endl; cout << "********************************************" << endl << endl; } //************************************享元工厂类************************** map<string, CWeight*> CChessFac::mpChess; CWeight* CChessFac::GetChess(string color) { CWeight* pChess = mpChess[color]; if(pChess == NULL){ pChess = new CFly(color); mpChess[color] = pChess; } return pChess; } void CChessFac::RemoveAll() { cout << "Before deleting... size = " << mpChess.size() << endl; for(map<string, CWeight*>::iterator it = mpChess.begin(); it != mpChess.end(); ){ cout << it->first << " : " << it->second << endl; CWeight* pWeight = it->second; delete pWeight; it = mpChess.erase(it); } cout << "After deleted... size = " << mpChess.size() << endl; }
//测试客户端
void main() { CWeight* pChess1 = CChessFac::GetChess("Black"); CWeight* pChess2 = CChessFac::GetChess("White"); CWeight* pChess3 = CChessFac::GetChess("Black"); cout << "pChess1 : " << pChess1 << endl; cout << "pChess2 : " << pChess2 << endl; cout << "pChess3 : " << pChess3 << endl; pChess1->Disp(CPos(10,10)); pChess2->Disp(CPos(20,20)); pChess3->Disp(CPos(30,30)); CChessFac::RemoveAll(); }