1. 程式人生 > >再戰設計模式(十一)之享元模式

再戰設計模式(十一)之享元模式

getc mage pub 維護 pan 模式 har 創建 vat

享元模式

場景:

內存屬於稀缺資源,不要隨便浪費。如果有很多個完全相同或相似的 對象,我們可以通過享元模式,節省內存.

核心:

本質:享元模式以共享的方式高效地支持大量細粒度對象的重用 享元對象能做到共享的關鍵是區分了內部狀態和外部狀態 內部狀態:可以共享,不會隨環境變化而改變 外部狀態:不可以共享,會隨環境變化而改變 現在有個需求,需要為圍棋設置一個程序,那麽圍棋的棋子改如何設計?總共有很多黑子和白子,難道我們需要為每一個棋子生成一個對象嗎? 技術分享圖片

顯然這樣的設計是不合理的.這個時候我們就可以用到享元模式!

類圖:如下

技術分享圖片

類圖的看比較復雜.我們來剖析下 chessFlyWeight:是一個接口,聲明了一些公共的方法,這些方法可以向外提供內部狀態,以及設置外部的狀態 ChessFlyWeightImpl: 是一個享元對象的實例,可以存儲內部狀態(因為可以共享) ,可以獲取外部狀態的屬性.如 x y ChessCoordinateConcrete: 是享元對象的外部狀態不可以共享,,可以隨意設置 ChessFlyWeightFactory : 就是通過內部狀態.獲取對象..就像我們平時用的緩存一樣.我把他設置成單例的了. client: 可以具體的調用這裏就不多說了.

代碼:

/**
 * 享元類
 * @Created by xiaodao
 */
public interface ChessFlyWeight {

    void setColor(String color );
    String getColor();
    void display(ChessCoordinateConcrete c );

}

/**
 * 為內部對象,提供享元存儲.!!
 * @Created by xiaodao
 */
public class ChessFlyWeightImpl implements ChessFlyWeight {
    
private String color; public ChessFlyWeightImpl(String color) { this.color = color; } public void setColor(String color) { this.color = color; } public String getColor() { return this.color; } public void display(ChessCoordinateConcrete c) { System.out.println(
"chess‘s color = "+ color); System.out.println("chess;s position x = "+ c.getX() +"----- y = "+ c.getY()); } } /** * 不可共享的外部結構 * @Created by xiaodao */ public class ChessCoordinateConcrete { private int x,y; public ChessCoordinateConcrete(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } /** * 享元 工廠 返回 接口... * @Created by xiaodao */ public class ChessFlyWeightFactory { private static ChessFlyWeightFactory instance= new ChessFlyWeightFactory(); private static HashMap<String,ChessFlyWeight> map = new HashMap<String, ChessFlyWeight>(); public ChessFlyWeight getChess(String color){ if(map.get(color) !=null){ return map.get(color); }else{ ChessFlyWeight chessFlyWeight = new ChessFlyWeightImpl(color); map.put(color,chessFlyWeight); return map.get(color); } } private ChessFlyWeightFactory() { } public static ChessFlyWeightFactory getInstance(){ return instance; } }
/**
 * @Created by xiaodao
 */
public class Client {

    public static void main(String[] args) {
        ChessFlyWeightFactory c =  ChessFlyWeightFactory.getInstance();

        ChessFlyWeight chess1 = c.getChess("黑色");

        chess1.display(new ChessCoordinateConcrete(10,20));

        ChessFlyWeight chess2 = c.getChess("黑色");
        System.out.println("-----------------");
        chess2.display(new ChessCoordinateConcrete(20,30));

        System.out.println(chess1);
        System.out.println(chess2);


    }

}

獲取到的結果:

chess‘s color = 黑色
chess;s position x = 10----- y = 20
-----------------
chess‘s color = 黑色
chess;s position x = 20----- y = 30
[email protected]
[email protected]

這樣的運行之後..我們就可以獲取到同一個對象,但是他的外部不可共享的屬性確不一樣..這就可以節省很多內存空間.

角色:

享元模式實現:

– FlyweightFactory享元工廠類
• 創建並管理享元對象,享元池一般設計成鍵值對

– FlyWeight抽象享元類

• 通常是一個接口或抽象類,聲明公共方法,這些方法可以向外界提供對象 的內部狀態,設置外部狀態。

– ConcreteFlyWeight具體享元類
• 為內部狀態提供成員變量進行存儲

– UnsharedConcreteFlyWeight非共享享元類

• 不能被共享的子類可以設計為非共享享元類

總結:

享元模式,我們在工作中很少用,寫起來比較復雜.維護也不好維護,但是我們還是需要了解,這樣對閱讀源碼是比較友好的.

優點:

  1. 極大的減少了內存中的對象數量
  2. 相同或者相似的對象內存中只有一份,節省空間
  3. 外部狀態相對獨立,不影響內部的屬性

缺點:

  1. 模式比較復雜.看上面的類圖就知道,感覺不夠清晰,是程序邏輯復雜化
  2. 為了使對象可以共享,享元模式需要將享元對象的狀態外部化,而讀取外部狀態使得運行時間變長。 用時間換取了空間

JDK或者項目中的使用

string 也是使用的享元模式,共享常量池.

integer: 中也使用了

   public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
     Integer a = Integer.valueOf(100);
        Integer b = 100;

        Integer c =Integer.valueOf(1000);
        Integer d = Integer.valueOf(1000);
        System.out.println(a==b);
        System.out.println(c==d);

true
false

integer 最小是-128 最大是127 在緩存中,當然也可以設置.也是使用的享元模式

數據連接池還有各種pool 也是使用的這個模式

再戰設計模式(十一)之享元模式