首先来看一个情景,我们在写文档的时候,有很多的字,但是这些字难道真的一个一个独立的对像吗?如果真的是一个一个独立真实的对象,那么内存就会爆掉的。大家可能听说过字库,我们看到的字都是字库里面的,每个显示的字都是字库里面的,每个字在字库里只会有一个对象,那么就意味着文档里的相同的字都会指向同一个对象,这样的好处是什么呢?可以节省大量的资源。
享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。
Flyweight类,它是所有具体享元类的父类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
ConcreteFlyweight是继承Flyweight子类或实现Flyweight接口,并为内部状态增加存储空间。
UnsharedFlyweight是指那些不需要共享的Flyweight子类。因为Flyweight接口共享成为可能,但它并不强制共享。
FlyweightFactory,是一个享元工厂,它主要是用来确保合理的共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
注意在这种模式中,客户端不在直接和元素交互,而是和工厂交互,即取字符的时候不是new一个字符出来,而是通过工厂里面的接口获取。
应用场景:如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时应该考虑使用该模式;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以使用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
#include<iostream>
#include<string>
#include<map>
using namespace std;
//模拟一个0-9数字字符库,
class Flyweight//所有字符的基类
{
public:
virtual void Operation() = 0;//对字符的操作,至少要显示字符
virtual ~Flyweight()
{}
};
class ConcreteFlyweight : public Flyweight //具体的字符,0,1,2,3,4,5.。。。。
{
private:
char ch;
public:
ConcreteFlyweight(char _ch) :ch(_ch)
{}
void Operation()
{
cout << "char=" << ch << endl;
}
};
class FlyweightFactory//一个字符生产工厂,取字符的地方
{
private:
map<char, Flyweight*>m;//每一个字符都有唯一的对象
public:
FlyweightFactory()
{
m.insert(make_pair('0', new ConcreteFlyweight('0')));//一开支字符库里面的字符
m.insert(make_pair('1', new ConcreteFlyweight('1')));
m.insert(make_pair('2', new ConcreteFlyweight('2')));
m.insert(make_pair('3', new ConcreteFlyweight('3')));
}
Flyweight* GetFlyweight(char key)//获取字符
{
if (m.find(key) == m.end())//字符库里没有这个字符,就添加一个字符
{
m.insert(make_pair(key, new ConcreteFlyweight(key)));
}
return m[key];
}
int FlyweightCount()//字符数量的大小
{
return m.size();
}
~FlyweightFactory()
{
map<char, Flyweight*>::iterator p = m.begin();
for (; p != m.end(); p++)
{
Flyweight *fp = p->second;
delete fp;
}
}
};
int main()
{
FlyweightFactory* f = new FlyweightFactory();
Flyweight* f0 = f->GetFlyweight('0');
f0->Operation();
Flyweight* f1 = f->GetFlyweight('1');
f1->Operation();
Flyweight* f2 = f->GetFlyweight('2');
f2->Operation();
Flyweight* f5 = f->GetFlyweight('5');
f5->Operation();
Flyweight* f8 = f->GetFlyweight('8');
f8->Operation();
Flyweight* f00 = f->GetFlyweight('0');//虽然又需要一个0,但是两个0共享一个对象
f00->Operation();
cout << "字符库大小:" << f->FlyweightCount() << endl;
delete f;
}