思考享元模式
①享元模式的本质:分离与共享。享元模式的关键在于分离变与不变,把不变部分作为享元对象的内部状态,而变化部分则作为外部状态,由外部来维护.这样享元对象就能够被共享,从而减少对象的数量,并节省大量的内存空间。
②享元模式的变与不变:为什么在一个地方要预留接口,一个常见的原因是这里存在变化,可能在今后需要扩展或改变己有的实现,而预留接口作为“可插入性的保证”
③享元对象:又有共享(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();
}