意图:运用共享技术有效地支持大量细粒度的对象.
适用性:
1 一个应用程序使用了大量的对象
2 完全由于使用大量的对象,造成很大的存储开销
3 对象的大多数状态都可变为外部状态
4 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
5 应用程序不依赖对象标识.由于Flyweight对象可以被共享,对于概念明显有别的想对象,标识测试将返回真值.
结构:
下面的对象图说明了如何共享flyweight
参与者:
Flyweight:描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。
ConcreteFlyweight:实现Flyweight接口,并为内部状态增加存储空间。该对象是共享的,它所存储的状态必须是内部的,即,必须独立于ConcreteFlyweight对象的场景。
UnsharedConcreteFlyweight:并非所有的flyweight子类都需要被共享。Flyweight接口使贡献成为可能,但它并不强制共享。在flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
FlyweightFactory:创建并管理flyweight对象;确保合理地共享flyweight.当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(不存在的话)
用户不应该直接对ConcreteFLyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,这样保证对它们适当地进行共享。
效果:
存储节约由以下决定:
因为共享,实例总数减少的数目;对象内部状态的平均数目;外部状态时计算的还是存储的。
两种方法节约存储:用共享减少内部状态的消耗,用计算时间换取对外部状态的存取。
实现:
1 删除外部状态:模式的可用性很大程度上取决于是否容易识别外部状态并将它从共享对象中删除。理想状态是:外部状态可由一个单独的对象结构计算得到,且该结构的存储要求很少。
2 管理共享对象:因为对象是共享的,不能直接对它们进行实例化,应该用flyweightfactory
适用性:
1 一个应用程序使用了大量的对象
2 完全由于使用大量的对象,造成很大的存储开销
3 对象的大多数状态都可变为外部状态
4 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
5 应用程序不依赖对象标识.由于Flyweight对象可以被共享,对于概念明显有别的想对象,标识测试将返回真值.
结构:
下面的对象图说明了如何共享flyweight
参与者:
Flyweight:描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。
ConcreteFlyweight:实现Flyweight接口,并为内部状态增加存储空间。该对象是共享的,它所存储的状态必须是内部的,即,必须独立于ConcreteFlyweight对象的场景。
UnsharedConcreteFlyweight:并非所有的flyweight子类都需要被共享。Flyweight接口使贡献成为可能,但它并不强制共享。在flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
FlyweightFactory:创建并管理flyweight对象;确保合理地共享flyweight.当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(不存在的话)
Clinet:维持一个对flyweight的引用;计算或存储一个(多个)flyweight的外部状态。
协作:
flyweight是一个共享对象,可以同时在多个场景中使用,并且每个场景中flyweight都可以作为一个独立的对象。flyweight不能对它所运行的场景做出任何假设。这里就有一个内部状态和外部状态。
用户不应该直接对ConcreteFLyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,这样保证对它们适当地进行共享。
效果:
存储节约由以下决定:
因为共享,实例总数减少的数目;对象内部状态的平均数目;外部状态时计算的还是存储的。
两种方法节约存储:用共享减少内部状态的消耗,用计算时间换取对外部状态的存取。
实现:
1 删除外部状态:模式的可用性很大程度上取决于是否容易识别外部状态并将它从共享对象中删除。理想状态是:外部状态可由一个单独的对象结构计算得到,且该结构的存储要求很少。
2 管理共享对象:因为对象是共享的,不能直接对它们进行实例化,应该用flyweightfactory
产生管理flyweight对象。flyweightfactory经常使用关联存储。共享还意味着某种形式的引用计数和垃圾回收,所以当一个flyweigh不再使用时,可以回收它的存储空间
相关模式:
flyweight通常和Composite模式结合起来,用共享叶节点的有向无环图实现一个逻辑上的层次结构
最好用flyweight来实现state和strategy模式
享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生成大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数外基本上都是相同的,有时可以大幅度减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时传递进来,就可以通过共享大幅度的减少单个实例的数目。
如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就因该考虑使用flyweight,还有如果对象的大多数状态可以为外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,这时也考虑用flyweight.
//享元模式:运用共享技术有效地支持大量细粒度的对象
#include <iostream>
#include <string>
#include <map>
using namespace std;
//User,外部状态类
class User
{
public:
User(string name) : _name(name)
{
}
string Name()
{
return _name;
}
private:
string _name;
} ;
//享元抽象类
class WebSite
{
public:
virtual void Use(User* user) = 0;
} ;
class ConcreteWebSite : public WebSite
{
public:
ConcreteWebSite(string name) : _name(name)
{
}
void Use(User* user)
{
cout << "网站分类:" << _name << " 用户:" << user->Name() << endl;
}
private:
string _name;
};
//网站工厂类
class WebSiteFactory
{
public:
WebSiteFactory()
{
}
//获得网站分类,共享相同的网站
WebSite* GetWebSiteCategory(string key)
{
if (flyweights.find(key) == flyweights.end())
flyweights.insert(make_pair(key, new ConcreteWebSite(key)));
return (WebSite*)(flyweights[key]);
}
//返回网站分类总数
int GetWebSiteCount()
{
return flyweights.size();
}
private:
//用map来存放网址,相同类型的只保存一份
map<string, WebSite*> flyweights;
};
int main()
{
WebSiteFactory f;
WebSite* fx = f.GetWebSiteCategory("产品展示");
fx->Use(new User("小菜"));
WebSite* fy = f.GetWebSiteCategory("产品展示");
fy->Use(new User("大鸟"));
WebSite* fz = f.GetWebSiteCategory("产品展示");
fx->Use(new User("娇娇"));
WebSite* f1 = f.GetWebSiteCategory("博客");
f1->Use(new User("老顽童"));
WebSite* f2 = f.GetWebSiteCategory("博客");
f2->Use(new User("桃谷六仙"));
WebSite* f3 = f.GetWebSiteCategory("博客");
f3->Use(new User("南海鳄神"));
cout << "得到网站分类总数为:" << f.GetWebSiteCount() << endl;
system("pause");
return 0;
}