Java描述設計模式(18):享元模式

本文源碼:GitHub·點這裏 || GitEE·點這裏java

1、使用場景

應用代碼git

public class C01_InScene {
    public static void main(String[] args) {
        String c0 = "cicada" ;
        String c1 = "cicada" ;
        System.out.println(c0 == c1); // true
    }
}

String類型就是使用享元模式。String對象是final類型,對象一旦建立就不可改變。在JAVA中字符串常量都是存在常量池中的,JAVA會確保一個字符串常量在常量池中只有一個拷貝,其中c0和c1就是一個字符串常量。結果爲:true,說明c0和c1兩個引用都指向了常量池中的同一個字符串常量"cicada"。這樣的設計避免了在建立N多相同對象時所產生的沒必要要的大量的資源消耗。github

2、享元模式

一、基礎簡介

享元模式是對象的結構模式。享元模式以共享的方式高效地支持大量的細粒度對象。經常使用於系統底層開發,解決系統的性能問題。像數據庫鏈接池,裏面都是建立好的鏈接對象,在這些鏈接對象中有須要的則直接拿來用,避免從新建立。數據庫

二、模式圖解

三、核心角色

  • 抽象享元角色

給出一個抽象接口,以規定具體享元角色要實現的方法。緩存

  • 具體享元角色

實現抽象享元角色所規定出的接口。若是有內部狀態的話,必須爲內部狀態提供存儲能力。ide

  • 享元工廠角色

負責建立和管理享元角色。必須保證享元對象能夠被系統選擇性共享。當一個客戶端對象調用一個享元對象的時候,享元工廠角色會檢查系統中是否已經有一個符合要求的享元對象。若是已經存在,直接返回該對象;若是系統中沒有該享元對象,享元工廠角色就應當建立該享元對象。源碼分析

四、內部外部狀態

  • 內部狀態指對象共享出來的信息,存儲在享元對象內部且不會隨環境的改變而改變。
  • 外部狀態指對象得以依賴的一個標記,能夠隨環境改變而改變的、不可共享的狀態。

五、源碼實現

public class C02_FlyWeight {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight fly = factory.factoryMethod('c');
        fly.printState("One");
        fly = factory.factoryMethod('d');
        fly.printState("Two");
        fly = factory.factoryMethod('c');
        fly.printState("San");
        // 調用了三次工廠方法,只建立了兩個對象
        factory.poolInfo();
    }
}
/**
 * 抽象享元角色類
 */
interface Flyweight {
    void printState (String state);
}
/**
 * 具體享元角色類
 */
class ConcreteFlyweight implements Flyweight {
    private Character innerState = null;
    public ConcreteFlyweight (Character state){
        this.innerState = state;
    }
    @Override
    public void printState(String state) {
        System.out.println("內部狀態:" + this.innerState);
        System.out.println("外部狀態:" + state);
    }
}
/**
 * 享元工廠角色類
 */
class FlyweightFactory {
    // 模擬數據池
    private Map<Character,Flyweight> pool = new HashMap<>();
    public Flyweight factoryMethod (Character state){
        //先從緩存中查找對象
        Flyweight fly = pool.get(state);
        if(fly == null){
            fly = new ConcreteFlyweight(state);
            pool.put(state, fly);
        }
        return fly;
    }
    public void poolInfo (){
        System.out.println("數據池:"+pool);
    }
}

3、JDK應用場景

  • 測試代碼塊
public class C03_Integer {
    public static void main(String[] args) {
        Integer c1 = Integer.valueOf(127),c2 = Integer.valueOf(127) ;
        Integer c3 = new Integer(127),c4 = new Integer(127) ;
        boolean flag1 = c1==c2 ,flag2 = c2==c3,flag3 = c3==c4 ;
        // true;false;false
        System.out.println(flag1+";"+flag2+";"+flag3);
        Integer c5 = Integer.valueOf(222),c6=Integer.valueOf(222) ;
        // false
        System.out.println(c5==c6);
    }
}
  • 源碼分析
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

這裏valueOf方法的意思就是,若是傳入的數據在 (-128) 到 (127) 之間,則從緩存中直接返回,不然建立一個新的Integer對象。性能

4、模式總結

享元模式可以解決重複對象的內存浪費的問題,當系統中有大量類似對象,須要緩衝池時。不需一直建立新對象,能夠從緩衝池裏拿。這樣能夠下降系統內存,同時提升效率。經典的應用場景就是池技術,String常量池、數據庫鏈接池、緩衝池等等都是享元模式的應用,享元模式是池技術的重要實現方式。享元模式使得系統更加複雜。爲了使對象能夠共享,須要時刻管理對象的狀態變化,這使得程序的邏輯變得複雜。測試

5、源代碼地址

GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

相關文章
相關標籤/搜索