享元模式是一个结构性设计模式,可以通过共享相近的状态来减少系统的存储开销。当一个系统需要创建很多对象,并且这些对象共享一些状态时我们可以考虑使用享元模式。
运用共享技术有效地支持大量细粒度的对象。
1.模式适用性
- 一个系统使用了大量的对象
- 由于使用大量对象,造成很大的存储开销
- 对象的大多数状态可变为外部状态
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
2.模式结构
考虑我们在开发一个五子棋游戏,五子棋棋子需要由棋子在棋盘上的坐标和颜色表示,如果没有使用享元模式,那么五子棋游戏的结构可能是下面这个样子的。
发现系统中Color对象可能只会创建colorWithe和colorBlack两种对象,我们可以使用享元模式共享Color。使用享元模式的结构如下。
对Color对象进行共享节约了存储共享,在大量使用的情况下,这个空间的节约是是很客观的。享元模式结构图所下所示。
(1)FlyweightFactory: 享元工厂,通过此工厂请求享元实例,如果享元已经存在则返回存在的享元,否则创建新的享元。
(2)Flyweight: 享元抽象接口,统一享元的使用。
(3)ConcreteFlyweight: 具体的享元实现。
(4)UnsharedConcreteFlyweight: 实现享元接口,可统一管理,但这个子类不强制共享。
3.实现
#include <iostream>
#include <map>
using namespace std;
class Flyweight
{
public:
virtual ~Flyweight(){};
virtual void Operation(int externState) = 0;
};
class ConcreteFlyweight : public Flyweight
{
public:
void Operation(int externState)
{
cout << "ConcreteFlyweight:" << externState << endl;
}
};
class UnsharedConcreteFlyweight : public Flyweight
{
public:
void Operation(int externState)
{
cout << "UnsharedConcreteFlyweight:" << externState << endl;
}
};
class FlyweightFactory
{
private:
map<char, Flyweight*> flyweights;
public:
FlyweightFactory()
{
flyweights['X'] = new ConcreteFlyweight();
flyweights['Y'] = new ConcreteFlyweight();
flyweights['Z'] = new ConcreteFlyweight();
}
~FlyweightFactory()
{
delete flyweights['X'];
delete flyweights['Y'];
delete flyweights['Z'];
}
Flyweight* GetFlyweight(char key)
{
return flyweights[key];
}
};
int main(int argc, char *argv[])
{
int externState = 1;
FlyweightFactory f;
Flyweight *fx = f.GetFlyweight('X');
fx->Operation(externState++);
Flyweight *fy = f.GetFlyweight('Y');
fy->Operation(externState++);
Flyweight *fz = f.GetFlyweight('Z');
fz->Operation(externState++);
UnsharedConcreteFlyweight *uf = new UnsharedConcreteFlyweight();
uf->Operation(externState++);
delete uf;
}
4.总结
共享的Flyweight越多,存储节约也就越多,节约量随着共享状态的增多而增大。当对象使用大量的内部及外部状态,并且外部状态是计算出来的而非存储的时候,节约量将达到最大。所以,可以使用两种方法来节约存储:用共享减少内部状态的消耗;用计算时间换取对外部状态的存储。