享元模式(Flyweight Pattern)是池技術的重要實現方式,可以降低大量重覆的、細粒度的類在記憶體中的開銷。 定義: 使用共用對象可有效地支持大量的細粒度對象。 以共用的方式高效地支持大量的細粒度對象。享元對象能做到共用的關鍵是區分內部狀態(Internal State)和外部狀態(Exte ...
享元模式(Flyweight Pattern)是池技術的重要實現方式,可以降低大量重覆的、細粒度的類在記憶體中的開銷。
定義:
- 使用共用對象可有效地支持大量的細粒度對象。
- 以共用的方式高效地支持大量的細粒度對象。享元對象能做到共用的關鍵是區分內部狀態(Internal State)和外部狀態(External State)。
- 內部狀態是存儲在享元對象內部的、可以共用的信息,並且不會隨環境改變而改變。
- 外部狀態是隨環境改變而改變且不可以共用的狀態。享元對象的外部狀態必須由客戶端保存,併在享元對象被創建後,在需要使用的時候再傳入到享元對象內部。
享元模式的類圖如下所示。
享元模式具有以下4個角色:
- 抽象享元(Flyweight)角色:對享元類進行抽象,需要外部狀態的操作可以通過參數的形式將外部狀態傳入。
- 具體享元(ConcreteFlyweight)角色:實現抽象享元定義的業務,註意享元對象的內部狀態必須與環境無關,從而使得享元對象可以在系統內共用。
- 享元工廠(FlyweightFactory)角色:構造一個池容器,負責創建和管理享元角色,並提供從池容器中獲得對象的方法,保證享元對象可以被系統適當的共用。當一個客戶端對象請求一個享元對象時,享元工廠角色會檢查系統中是否已經有一個符合要求的享元對象。如果已經有了,享元工廠則提供這個已有的享元對象,否則創建一個合適的享元對象。
- 客戶端角色:自行存儲所有享元對象的外部狀態。
Flyweight.java
public interface Flyweight { // 業務方法 public abstract void operation(String extrinsicState); }
ConcreteFlyweight.java
public class ConcreteFlyweight implements Flyweight { private String intrinsicState;// 內部狀態 public ConcreteFlyweight(String intrinsicState) { this.intrinsicState = intrinsicState; } @Override public void operation(String extrinsicState) { System.out.println("內部狀態" + intrinsicState + ",外部狀態:" + extrinsicState); } @Override public String toString() { return "內部狀態=" + intrinsicState; } }
FlyweightFactory.java
public class FlyweightFactory { private static Map<String, Flyweight> pool = new HashMap<String, Flyweight>(); private FlyweightFactory(){} // 私有構造方法 public static Flyweight getFlyweight(String intrinsicState) { Flyweight flyweight = pool.get(intrinsicState); if (flyweight == null) { flyweight = new ConcreteFlyweight(intrinsicState); pool.put(intrinsicState, flyweight); } return flyweight; } }
Client.java
public class Client { public static void main(String[] args) { for (int i = 0; i < 5; i++) { Flyweight flyweight = FlyweightFactory.getFlyweight("" + i); flyweight.operation("" + (i + 1)); } Flyweight flyweight = FlyweightFactory.getFlyweight("0"); System.out.println(flyweight); } }
優點:
- 大幅減少記憶體中對象的數量,降低程式記憶體的占用,提高性能。但是相應付出的代價也很高。
缺點:
- 享元模式增加了系統的複雜性,需要分出外部狀態和內部狀態,而且內部狀態具有固化特性,不應該隨外部狀態改變而改變,使得程式邏輯複雜化。
- 享元對象將享元對象的狀態外部化,而讀取外部狀態使得運行時間變長。
使用場景:
- 系統中有大量相似對象,這些對象耗費大量記憶體。
- 細粒度的對象都具備較接近的外部狀態,而且內部狀態與環境無關,即對象沒有特定身份。
- 需要緩衝池的場景。
摘自:
青島東合信息技術有限公司 . 設計模式(Java版) . 電子工業出版社,2012,103-105.