模式动机(Flyweight Pattern):顾名思义,享元模式就是运用共享技术解决大量细粒度对象的复用问题。在享元模式中,由工厂负责维护一个享元池(Flyweight Pool),用于存储具有相同内部状态的一些对象。所谓内部状态,是指一个对象的特征,我们把大多数该类对象的不变特征确定为共享特征,将其抽象为一个类放到享元池中,对于可变的部分可以通过外部状态参数传入来解决。这样的话,如果客户要使用该类型的对象,只需通过工厂从享元池中取出即可,只有在享元池中不存在的对象才会被工厂创建出来。
模式结构图:
模式代码:
bt_享元模式.h:
#ifndef FP_H
#define FP_H
#include <iostream>
#include <map>
using namespace std;
/*
抽象享元接口,用于接受外部状态
*/
class Flyweight
{
public:
virtual ~Flyweight(){ }
virtual void Operation(string extrinsicState) = 0;
};
/*
包含共享内部状态的具体享元类
*/
class ConcreteFlyweight : public Flyweight
{
public:
ConcreteFlyweight(){ intrinsicState = "intrinsic state"; }
virtual void Operation(string extrinsicState)
{
cout << "使用共享内部状态:" << intrinsicState << endl;
cout << "根据外部状态[ " << extrinsicState << " ]来进行工作" << endl;
}
private:
string intrinsicState; // 共享的内部状态
};
/*
非共享具体享元类,其中包含了不能共享的内部状态
*/
class UnsharedConcreteFlyweight : public Flyweight
{
public:
UnsharedConcreteFlyweight()
{
intrinsicState = "intrinsic state";
unSharedState = "unShared state";
}
virtual void Operation(string extrinsicState)
{
cout << "使用共享内部状态:" << intrinsicState << endl;
cout << "根据外部状态[ " << extrinsicState << " ]来进行工作" << endl;
cout << "直接使用非共享内部状态:" << unSharedState << endl;
}
private:
string intrinsicState; // 共享的内部状态
string unSharedState; // 不能共享的内部状态
};
/*
享元工厂类,用于创建并管理享元对象
*/
class FlyweightFactory
{
public:
Flyweight* GetFlyweight(string key)
{
if(flyweights.find(key) == flyweights.end())
{
cout << ">>>共享池中不存在该类型的对象,正在创建中..." << endl;
Flyweight* fw = new ConcreteFlyweight;
flyweights.insert(make_pair(key, fw));
return fw;
}
else
{
cout << ">>>共享池中已有该类型对象,可以立即使用" << endl;
return flyweights[key];
}
}
private:
map<string, Flyweight*> flyweights;
};
#endif // FP_H
#include "bt_享元模式.h"
int main()
{
cout << "***** 享元模式测试 *****" << endl;
cout << endl;
FlyweightFactory* ff = new FlyweightFactory;
Flyweight* fw = ff->GetFlyweight("benxin"); // 第一次创建时不存在该对象
fw->Operation("tuzi");
cout << endl;
Flyweight* fw2 = ff->GetFlyweight("benxin"); // 第二次创建时直接返回该对象
fw2->Operation("tuzi");
cout << endl;
cout << "<<<直接使用非共享具体享元状态>>>" << endl; // 非共享内部状态可以直接实例化来使用
Flyweight* fw3 = new UnsharedConcreteFlyweight;
fw3->Operation("tuzi");
delete fw3;
delete fw;
delete ff;
return 0;
}
模式分析:
1> 享元模式中,选择频繁使用的类作为享元类,因为系统调用工厂也要产生时间上的开销,使用享元模式必须确保节约的空间开销是值得的;
2> 只有不会随着使用环境改变的状态才可以被设为共享状态;有些状态虽为内部状态,但是并不适合共享,对于这类状态,客户可以越过工厂直接实例化进行使用。
3> 享元模式的使用情况主要存在于系统中需要重复使用相同或类似的对象,如果每次都重复创建,可能会消耗大量内存空间,比如,文档编辑器中的字符类就适合作为享元类,而字符的位置参数适合作为外部状态使用,这样就可以加快文档的处理速度。