設計模式學習筆記(二十二)—FlyWeight享元模式
Posted on 2008-01-26 13:45 flustar 閱讀(1658) 評論(0) 編輯 收藏 所屬分類: Design Patterns一、FlyWeight模式定義:
運用共享技術有效地支持大量細粒度對象。
二、模式解說
也就是說在一個系統中如果有多個相同的對象,那么只共享一份就可以了,不必每個都去實例化一個對象。在Flyweight模式中,由于要產生各種各樣的對象,所以在Flyweight(享元)模式中常出現Factory模式。Flyweight的內部狀態是用來共享的,Flyweight factory負責維護一個對象存儲池(Flyweight Pool)來存放內部狀態的對象。Flyweight模式是一個提高程序效率和性能的模式,會大大加快程序的運行速度。
三、結構圖
享元模式所涉及的角色有抽象享元角色、具體(單純)享元角色、復合享元角色、享員工廠角色,以及客戶端角色等。
抽象享元角色(Flyweight):此角色是所有的具體享元類的超類,為這些類規定出需要實現的公共接口或抽象類。那些需要外蘊狀態(External State)的操作可以通過方法的參數傳入。抽象享元的接口使得享元變得可能,但是并不強制子類實行共享,因此并非所有的享元對象都是可以共享的。
具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定的接口。如果有內蘊狀態的話,必須負責為內蘊狀態提供存儲空間。享元對象的內蘊狀態必須與對象所處的周圍環境無關,從而使得享元對象可以在系統內共享。有時候具體享元角色又叫做單純具體享元角色,因為復合享元角色是由單純具體享元角色通過復合而成的。
復合享元(UnsharableFlyweight)角色:復合享元角色所代表的對象是不可以共享的,但是一個復合享元對象可以分解成為多個本身是單純享元對象的組合。復合享元角色又稱做不可共享的享元對象。這個角色一般很少使用。
享元工廠(FlyweightFactoiy)角色:本角色負責創建和管理享元角色。本角色必須保證享元對象可以被系統適當地共享。當一個客戶端對象請求一個享元對象的時候,享元工廠角色需要檢查系統中是否已經有一個符合要求的享元對象,如果已經有了,享元工廠角色就應當提供這個已有的享元對象;如果系統中沒有一個適當的享元對象的話,享元工廠角色就應當創建一個新的合適的享元對象。
客戶端(Client)角色:本角色還需要自行存儲所有享元對象的外蘊狀態。
四、一個例子
import java.util.Hashtable;
/**
*
* @author <a href="mailto:flustar2008@163.com">flustar</a>
* @version 1.0
* Creation date: Jan 25, 2008 1:33:49 PM
*/
// "Flyweight"
abstract class Character
{
protected char symbol;
protected int width;
protected int height;
protected int ascent;
protected int descent;
protected int pointSize;
public abstract void Display(int pointSize);
}
// "ConcreteFlyweight"
class CharacterA extends Character
{
// Constructor
public CharacterA()
{
this.symbol = 'A';
this.height = 100;
this.width = 120;
this.ascent = 70;
this.descent = 0;
}
public void Display(int pointSize)
{
this.pointSize = pointSize;
System.out.println(this.symbol +
" (pointsize " + this.pointSize + ")");
}
}
// "ConcreteFlyweight"
class CharacterB extends Character
{
// Constructor
public CharacterB()
{
this.symbol = 'B';
this.height = 100;
this.width = 140;
this.ascent = 72;
this.descent = 0;
}
public void Display(int pointSize)
{
this.pointSize = pointSize;
System.out.println(this.symbol +
" (pointsize " + this.pointSize + ")");
}
}
// C, D, E, etc.
// "ConcreteFlyweight"
class CharacterZ extends Character
{
// Constructor
public CharacterZ()
{
this.symbol = 'Z';
this.height = 100;
this.width = 100;
this.ascent = 68;
this.descent = 0;
}
public void Display(int pointSize)
{
this.pointSize = pointSize;
System.out.println(this.symbol +
" (pointsize " + this.pointSize + ")");
}
}
// "FlyweightFactory"
class CharacterFactory
{
private Hashtable characters = new Hashtable();
public Character GetCharacter(char key)
{
// Uses "lazy initialization"
Character character = (Character)characters.get(key);
if (character == null)
{
switch (key)
{
case 'A': character = new CharacterA(); break;
case 'B': character = new CharacterB(); break;
//
case 'Z': character = new CharacterZ(); break;
}
characters.put(key, character);
}
return character;
}
}
// test application
public class Test
{
public static void main(String []args)
{
// Build a document with text
String document = "AAZZBBZB";
char[] chars = document.toCharArray();
CharacterFactory f = new CharacterFactory();
// extrinsic state
int pointSize = 10;
// For each character use a flyweight object
for(char c : chars)
{
pointSize++;
Character character = f.GetCharacter(c);
character.Display(pointSize);
}
}
}
五、 適用性
Flyweight模式的有效性很大程度上取決于如何使用它以及在何處使用它。當以下情況都成立時使用Flyweight模式。
1) 一個應用程序使用了大量的對象。
2) 完全由于使用大量的對象,造成很大的存儲開銷。
3) 對象的大多數狀態都可變為外部狀態。
4) 如果刪除對象的外部狀態,那么可以用相對較少的共享對象取代很多組對象。
5) 應用程序不依賴對象標識。
六、優缺點
1)享元模式使得系統更加復雜。為了使對象可以共享,需要將一些狀態外部化,這使得程序的邏輯復雜化。
2)享元模式將享元對象的狀態外部化,而讀取外部狀態使得運行時間稍微變長。
七、參考
《設計模式可復用面向對象軟件的基礎》
《Design Pattern Framework 2.0》