// // // // // // // // //
///2013.1.31
// // // // // // // // //
Flyweight模式,
有一个有趣的翻译:
——蝇量模式。
【核心】将大量粒度(小的)的对象进行共性与特殊性的分离,用'提取'代替'创建'重复的部分。
UML图:
其目的非常单纯,
在程序中大量应用的重复小数据,
就像这篇文章中的文字——例如'的',
在它重复大量出现的时候,
如果每一次的实现都为其实例化一次,
将会造成大量重复的开销。
为此,
Flyweight会将这些重复的归为一类(放到一个大字典中),
在需要的时候提取出来就好了。
当然即使是拥有共性的物体也可能具有各自的特殊性:
例如'的'有以下几种形式:
的 的 的 的
都是同一个字,
但却有不同的表现形式,
这种时候,
就是UML图中的没有进行共享的那一部分:
——外部状态的设计目的了。
代码实例:
【大致思路】
FlyWeight作为虚基类,其衍生类ConcreteFlyWeight在构造函数中将FlyWeight内部状态keyName(共享、通用的)初始化。
并通过Operation以及其参数——外部状态Style(如Color之类的)来创建不同形式的Key.
FlyWeightFactory拥有一个FlyWeight类型的集合,每次在创建相应Key的时候都检查是否已含有此KeyName,
如果有,则调用;没有,则创建。
#ifndef _FLYWEIGHT_H_
#define _FLYWEIGHT_H_
#include<iostream>
#include<string>
using namespace std;
class FlyWeight
{
public:
virtual void Operation(string style) = 0;
string getKeyName();
protected:
FlyWeight(string cn);
string keyName;
};
class ConcreteFlyWeight:public FlyWeight
{
public:
ConcreteFlyWeight(string key);
string getKeyName();
void Operation(string style);
};
#endif
FlyWeight.cpp
#include"FlyWeight.h"
using namespace std;
FlyWeight::FlyWeight(string cn)
{
this->keyName = cn;
}
string FlyWeight::getKeyName()
{
return this->keyName;
}
ConcreteFlyWeight::ConcreteFlyWeight(string cn):FlyWeight(cn)
{
}
void ConcreteFlyWeight::Operation(string style)
{
cout<<"KeyName: "<<keyName<<endl;
cout<<"Style: "<<style<<endl;
}
string ConcreteFlyWeight::getKeyName()
{
return this->keyName;
}
FlyWeightFactory,h
#ifndef _FLYWEIGHTFACTORY_H_
#define _FLYWEIGHTFACTORY_H_
#include"FlyWeight.h"
#include<vector>
class FlyWeightFactory
{
public:
FlyWeightFactory();
FlyWeight* getFlyWeight(string cn);
private:
std::vector<FlyWeight*> flyWeightPool;
};
#endif
FlyWeightFactory.cpp
#include"FlyWeightFactory.h"
using namespace std;
FlyWeightFactory::FlyWeightFactory()
{
}
FlyWeight* FlyWeightFactory::getFlyWeight(string key)
{
vector<FlyWeight*>::iterator itr;
for(itr = flyWeightPool.begin();itr != flyWeightPool.end();itr++)
{
if((*itr)->getKeyName() == key)
{
cout<<"Get this key: "<<key<<endl;
//If pool has this key.
return (*itr);
}
}
//If hasn't this key in the pool.Then Create...
FlyWeight* newFlyWeight = new ConcreteFlyWeight(key);
//And Add it to the pool.
flyWeightPool.push_back(newFlyWeight);
cout<<"Create this key: "<<key<<endl;
return newFlyWeight;
}
main.cpp
#include"FlyWeightFactory.h"
int main()
{
FlyWeightFactory* factory = new FlyWeightFactory();
FlyWeight* key1 = new ConcreteFlyWeight("Fly");
//Create and add to factory's pool.
factory->getFlyWeight("Fly")->Operation("Red Color");
std::cout<<std::endl;
//Get Key from factory's pool
factory->getFlyWeight("Fly")->Operation("Black Color");
return 0;
}
输出结果:
【注意事项】
此模式核心的地方是在于对比每个创建的对象是否拥有共同状态,
没有,则创建;有,就提取。
因此,代码中的getFlyWeight需要着重去理解。
当然,
作为讲解之用,
这里使用Vector,
其实更多时候,
应该用一个Hash表来作为集合收容这些FlyWeight(例如C#中的Dictionary)。
顺便一提,
笔者作为游戏开发者,
看到此模式的第一眼就想到了图片Texture的调用。
在制作游戏中,
一张图片总是会重复使用多次,
如果每次调用都重新创建的话,
那太过不环保。
因此很多优秀的引擎(例如Cocos2d系列),
都提供了一个图片池,
只需要将Sprite加入其中,
这样即使大量重复调用也不会比调用一次占更多内存(可忽略不计)。
其原理,
就是这个简单的FlyWeight模式。