// // // // // // // // //
///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
#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; }
#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
#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; }
#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模式。