运用共享技术有效地支持大量细粒度的对象。
2. 动机
有些应用程序得益于在其整个设计过程中采用对象技术,但简单化的实现代价极大。例如,大多数文档编辑器的实现都有文本格式化和编辑功能,这些功能在一定程度上是模块化的。面向对象的文档编辑器通常使用对象来表示嵌入的成分,例如表格和图形。尽管用对象来表示文档中的每个字符会极大地提高应用程序的灵活性,但是这些编辑器通常并不这样做。字符和嵌入成分可以在绘制和格式化时统一处理,从而在不影响其他功能的情况下能对应用程序进行扩展,支持新的字符集。应用程序的对象结构可以模拟文档的物理结构。
但这种设计的缺点在于代价太大。即使是一个中等大小的文档也可能要求成百上千的字符对象,这会耗费大量内存,产生难以接受的运行开销。所以通常并不是对每个字符都用一个对象来表示的。F l y w e i g h t模式描述了如何共享对象,使得可以细粒度地使用它们而无需高昂的代价。
f l y w e i g h t是一个共享对象,它可以同时在多个场景( c o n t e x t )中使用,并且在每个场景中f l y w e i g h t都可以作为一个独立的对象—这一点与非共享对象的实例没有区别。f l y w e i g h t不能对它所运行的场景做出任何假设,这里的关键概念是内部状态和外部状态之间的区别。内部状态存储于f l y w e i g h t中,它包含了独立于f l y w e i g h t场景的信息,这些信息使得f l y w e i g h t可以被共享。而外部状态取决于F l y w e i g h t场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给F l y w e i g h t。
Fl y w e i g h t模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模。例如,文档编辑器可以为字母表中的每一个字母创建一个f l y w e i g h t。每个f l y w e i g h t存储一个字符代码,但它在文档中的位置和排版风格可以在字符出现时由正文排版算法和使用的格式化命令决定。字符代码是内部状态,而其他的信息则是外部状态。
3. 适用性
F l y w e i g h t模式的有效性很大程度上取决于如何使用它以及在何处使用它。当以下情况都成立时使用F l y w e i g h t模式:
• 一个应用程序使用了大量的对象。
• 完全由于使用大量的对象,造成很大的存储开销。
• 对象的大多数状态都可变为外部状态。
• 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
• 应用程序不依赖于对象标识。由于F l y w e i g h t对象可以被共享,对于概念上明显有别的对
象,标识测试将返回真值。
4. 结构
5.C++举例
#ifndef FLYWEIGHT_H
#define FLYWEIGHT_H
#include <iostream>
#include <string>
#include <map>
using std::pair;
using std::cout;
using std::endl;
using std::string;
using std::map;
using std::iterator;
class CFont{
public:
string m_Font;
public:
CFont(){}
CFont(string temp): m_Font(temp){
}
void Show(){
cout<<m_Font<<endl;
};
};
class CChineseFont : public CFont{
public:
CChineseFont(string temp) : CFont(temp){}
};
class CEnglishFont : public CFont{
public:
CEnglishFont(string temp) : CFont(temp){}
};
class CFontFactory{
private:
map<string, CFont> m_FontPool;
public:
CFontFactory(){
}
CFont CreateFont(CFont temp){
if(m_FontPool.find(temp.m_Font)!=m_FontPool.end())
return m_FontPool[temp.m_Font];
m_FontPool.insert(pair<string, CFont>(temp.m_Font,temp));
return temp;
}
void Show(){
cout<<"The FontPool include: "<<endl;
for(map<string,CFont>::iterator it=m_FontPool.begin();it!=m_FontPool.end();it++)
cout<<it->first<<endl;
}
};
#endif
#include <iostream>
#include "FlyWeight.h"
int main(){
CChineseFont mFont1("Chinese");
CEnglishFont mFont2("English");
CFontFactory mBoss;
mBoss.CreateFont(mFont1);
mBoss.CreateFont(mFont2);
CChineseFont mFont3("Ancient");
mBoss.CreateFont(mFont3);
mBoss.Show();
CChineseFont mFont4("Ancient");
mBoss.CreateFont(mFont4);
mBoss.Show();
}