现在的位置: 首页 > 综合 > 正文

【2013.1.31】好朋友就是你的东西是我的,我的东西还是我的——Flyweight(使用Vector)

2018年02月19日 ⁄ 综合 ⁄ 共 2767字 ⁄ 字号 评论关闭

// // // // // // // // //

///2013.1.31

// // // // // // // // //

Flyweight模式,

有一个有趣的翻译:

——蝇量模式。

【核心】将大量粒度(小的)的对象进行共性与特殊性的分离,用'提取'代替'创建'重复的部分。

UML图:

其目的非常单纯,

在程序中大量应用的重复小数据,

就像这篇文章中的文字——例如'的',

在它重复大量出现的时候,

如果每一次的实现都为其实例化一次,

将会造成大量重复的开销。

为此,

Flyweight会将这些重复的归为一类(放到一个大字典中),

在需要的时候提取出来就好了。

当然即使是拥有共性的物体也可能具有各自的特殊性:

例如'的'有以下几种形式:

   

都是同一个字,

但却有不同的表现形式,

这种时候,

就是UML图中的没有进行共享的那一部分:

——外部状态的设计目的了。

代码实例:

【大致思路】

FlyWeight作为虚基类,其衍生类ConcreteFlyWeight在构造函数中将FlyWeight内部状态keyName(共享、通用的)初始化。

并通过Operation以及其参数——外部状态Style(如Color之类的)来创建不同形式的Key.

FlyWeightFactory拥有一个FlyWeight类型的集合,每次在创建相应Key的时候都检查是否已含有此KeyName,

如果有,则调用;没有,则创建。

FlyWeight.h

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

抱歉!评论已关闭.