享元模式 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);
}
}
};
實驗結果: