设计模式(22)–享元模式

Posted by Tango on April 11, 2016

享元模式是一个结构性设计模式,可以通过共享相近的状态来减少系统的存储开销。当一个系统需要创建很多对象,并且这些对象共享一些状态时我们可以考虑使用享元模式。

运用共享技术有效地支持大量细粒度的对象。

1.模式适用性

  • 一个系统使用了大量的对象
  • 由于使用大量对象,造成很大的存储开销
  • 对象的大多数状态可变为外部状态
  • 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象

2.模式结构

考虑我们在开发一个五子棋游戏,五子棋棋子需要由棋子在棋盘上的坐标和颜色表示,如果没有使用享元模式,那么五子棋游戏的结构可能是下面这个样子的。

Flyweight1

发现系统中Color对象可能只会创建colorWithe和colorBlack两种对象,我们可以使用享元模式共享Color。使用享元模式的结构如下。

Flyweight2

对Color对象进行共享节约了存储共享,在大量使用的情况下,这个空间的节约是是很客观的。享元模式结构图所下所示。

Flyweight2

(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越多,存储节约也就越多,节约量随着共享状态的增多而增大。当对象使用大量的内部及外部状态,并且外部状态是计算出来的而非存储的时候,节约量将达到最大。所以,可以使用两种方法来节约存储:用共享减少内部状态的消耗;用计算时间换取对外部状态的存储。