享元模式 Flyweight Pattern
1.定义
享元模式,以共享的方式高效地支持大量的细粒度的对象。通过复用内存中已存在的对象,
降低系统创建对象实例的性能消耗。
2.使用场景:
- 当系统中某个对象类型的实例较多的时候。
- 由于使用了大量的对象,造成了很大的存储开销。
- 对象的大多数状态都可变为外蕴状态。
- 在系统设计中,对象实例进行分类后,发现真正有区别的分类很少的时候。
3.模式解析
图示:
- 抽象享元类(Flyweight): 此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口或抽象类。那些需要外部状态(External State)的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。
- 具体享元类(ConcreteFlyweight):具体享元类实现了抽象享元类所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元类又称为单纯具体享元类,因为复合享元类是由单纯具体享元角色通过复合而成的。
- 不能共享的具体享元类(UnsharableFlyweight):不能共享的享元类,又叫做复合享元类。一个复合享元对象是由多个单享元对象组成,这些组成的对象是可以共享的,但是复合享元类本身并不能共享
- 享元工厂类(FlyweightFactoiy):享元工厂类负责创建和管理享元对象。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。
- 客户端(Client)角色:本角色还需要自行存储所有享元对象的外部状态。
4.总结:
享元模式是通过共享有效支持大量细粒度的对象,来提供应用程序的性能,节省系统中重复创建对象实例的性能消耗
5.代码实例:
#pragma once
#include <iostream>
using namespace std;
#include <map>
class Character
{
protected:
char symbol;
int width;
int height;
int ascent;
int descent;
int pointSize;
public:
virtual void Display(int pointSize) = 0;
};
class CharacterA : public Character
{
public:
CharacterA()
{
symbol = 'A';
height = 100;
width = 120;
ascent = 70;
descent = 0;
}
void Display(int _pointSize)
{
pointSize = _pointSize;
cout<<symbol<<" (pointsize "<< pointSize <<")"<<endl;
}
};
class CharacterB : public Character
{
public:
CharacterB()
{
symbol = 'B';
height = 100;
width = 140;
ascent = 72;
descent = 0;
}
void Display(int _pointSize)
{
pointSize = _pointSize;
cout<<symbol<<" (pointsize "<< pointSize <<")"<<endl;
}
};
class CharacterZ : public Character
{
public:
CharacterZ()
{
symbol = 'Z';
height = 100;
width = 100;
ascent = 68;
descent = 0;
}
void Display(int _pointSize)
{
pointSize = _pointSize;
cout<<symbol<<" (pointsize "<< pointSize <<")"<<endl;
}
};
/*
享元工厂类
*/
class CharacterFactory
{
public:
// 客户端通过这个函数请求享元对象
Character* GetCharacter(char key)
{
Character* character = nullptr;
map<char,Character*>::iterator it = _characters.find(key);
if( it != _characters.end() )
{
character = it->second ;
}
else
{ //没找到
switch (key)
{
case 'A':
character = new CharacterA();
break;
case 'B':
character = new CharacterB();
break;
case 'Z':
character = new CharacterZ();
break;
default:
break;
}
_characters.insert(make_pair(key,character));
}
return character;
}
private:
map<char,Character*> _characters;
};
class FlyweightPatternExample1
{
public:
void Start()
{
string document = "AAZZBBZB";
CharacterFactory *factory = new CharacterFactory();
int pointSize = 10;
for( int i = 0 ; i < document.size();i++ )
{
pointSize++;
Character* character = factory->GetCharacter(document[i]);
character->Display(pointSize);
}
}
};
实验结果: