java常見設計模式清單

1. 代理模式

  • 爲其他對象提供一種代理以控制對這個對象的訪問。
  • 和適配器模式的區別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類的接口。
  • 和裝飾器模式的區別:裝飾器模式爲了增強功能,而代理模式是爲了加以控制。

代理模式分爲靜態代理,動態代理以及Cglib代理三種

1. 靜態代理

  • 靜態代理在使用時,需要定義接口或者父類,被代理對象與代理對象一起實現相同的接口或者是繼承相同父類,然後代理對象中包含有被代理對象(作爲成員變量),然後通過代理對象執行被代理對象的方法。
  • 缺點:因爲代理對象需要與目標對象實現一樣的接口,所以會有很多代理類,類太多.同時,一旦接口增加方法,目標對象與代理對象都要維護。

2. 動態代理

  • 利用JDK的Proxy類,動態的在內存中構建代理對象(需要我們指定創建代理對象/目標對象實現的接口的類型)

3. Cglib代理

  • 上面的靜態代理和動態代理模式都是要求目標對象是實現一個接口的目標對象,但是有時候目標對象只是一個單獨的對象,並沒有實現任何的接口,這個時候就可以使用以目標對象子類的方式類實現代理,這種方法就叫做:Cglib代理。
  • Cglib是一個強大的高性能的代碼生成包,它可以在運行期擴展java類與實現java接口。
  • 廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,爲他們提供方法的interception(攔截)。
  • .需要引入cglib的jar文件,但是Spring的核心包中已經包括了Cglib功能。

spring的aop與代理模式

2. 策略模式

  • 定義一系列的算法,把它們一個個封裝起來, 並且使它們可相互替換。
  • 關鍵代碼:實現同一個接口。
  • 如果在一個系統裏面有許多類,它們之間的區別僅在於它們的行爲,那麼使用策略模式可以動態地讓一個對象在許多行爲中選擇一種行爲。行爲都實現同一個接口,對象可以動態的設置使用哪一種行爲。

3. 單例模式

單例對象能保證在一個JVM中,該對象只有一個實例存在。不用頻繁創建,節省系統開銷。

1. 懶漢式(非線程安全)

  • 懶漢式,線程不安全,不支持多線程。因爲沒有加鎖 synchronized。
public class Singleton1 {
/*  懶漢式,Lazy 初始化,線程不安全,不支持多線程。因爲沒有加鎖 synchronized*/
    private static Singleton1 singleton;
    private Singleton1() {}
    public static Singleton1 getInstance(){
        if(singleton == null) singleton = new Singleton1();
        return singleton;
    }   
}

2. 懶漢式(線程安全)

  • 懶漢式,線程安全,必須加鎖 synchronized 才能保證單例。
  • 但加鎖會影響效率。效率很低,99% 情況下不需要同步。
public class Singleton2 {
/*  懶漢式,Lazy 初始化,線程安全,必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。效率很低,99% 情況下不需要同步。
    優點:第一次調用才初始化,避免內存浪費。*/
    private static Singleton2 singleton;
    private Singleton2() {}
    public static synchronized Singleton2 getInstance(){
        if(singleton == null) singleton = new Singleton2();
        return singleton;
    }   
}

3. 懶漢式(雙重校驗鎖)

  • 懶漢式,Lazy初始化,雙重校驗鎖,採用兩個if判斷。
  • 安全且在多線程情況下能保持高性能。
public class Singleton4 {
/*  懶漢式,Lazy初始化,雙重校驗鎖,採用兩個if判斷
    安全且在多線程情況下能保持高性能。*/
    private volatile static Singleton4 singleton;
    private Singleton4(){};
    public static Singleton4 getInstance(){
        //檢查變量是否被初始化(不去獲得鎖),如果已被初始化立即返回這個變量。
        if (singleton == null) {
            synchronized (Singleton4.class) {
                if(singleton == null){
                    //第二次檢查變量是否已經被初始化:如果其他線程曾獲取過鎖,那麼變量已被初始化,返回初始化的變量。
                    singleton = new Singleton4();
                }
            }
        }
        return singleton;
    }
}

4. 懶漢式(靜態內部類)

  • 這種方式能達到雙檢鎖方式一樣的功效,但實現更簡單。
  • 關鍵:可以延遲加載。
  • 餓漢式中,只要 Singleton 類被裝載了,那麼 instance 就會被實例化(沒有達到 lazy loading 效果)。而這種方式是 Singleton 類被裝載了,instance 不一定被初始化。因爲 SingletonHolder 類沒有被主動使用,只有通過顯式調用 getInstance 方法時,纔會顯式裝載 SingletonHolder 類,從而實例化 instance。
public class Singleton5 {
/*  懶漢式,登記式/靜態內部類
    這種方式能達到雙檢鎖方式一樣的功效,但實現更簡單。關鍵:可以延遲加載
    第三種(餓漢式)只要 Singleton 類被裝載了,那麼 instance 就會被實例化(沒有達到 lazy loading 效果)
    而這種方式是 Singleton 類被裝載了,instance 不一定被初始化。因爲 SingletonHolder 類沒有被主動使用,
    只有通過顯式調用 getInstance 方法時,纔會顯式裝載 SingletonHolder 類,從而實例化 instance。*/
    private static class SingletonHolder{
        private static final Singleton5 INSTANCE = new Singleton5();
    }

    private Singleton5(){};

    public static final Singleton5 getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

5. 餓漢式

  • 餓漢式加載(非Lazy初始化)
  • 優點:沒有加鎖,執行效率會提高。
  • 缺點:類加載時就初始化,浪費內存。
public class Singleton3 {
/*  餓漢式加載(非Lazy初始化)
    優點:沒有加鎖,執行效率會提高。
    缺點:類加載時就初始化,浪費內存。*/
    private static Singleton3 singleton = new Singleton3();
    private Singleton3(){};
    public static Singleton3 getInstance(){
        return singleton;
    }
}

6. 餓漢式(枚舉類型)

  • 這種方式是 Effective Java 提倡的方式,它不僅能避免多線程同步問題,而且還自動支持序列化機制,防止反序列化重新創建新的對象,絕對防止多次實例化。
  • 原理:enum是通過繼承了Enum類實現的,Enum類是final的;enum僅有私有構造器,防止外部的額外構造;JVM禁止實現枚舉類型的readObject等方法。
public enum Singleton6 {
/*  餓漢式,枚舉類型
    這種方式是 Effective Java 提倡的方式,它不僅能避免多線程同步問題,而且還自動支持序列化機制,防止反序列化重新創建新的對象,絕對防止多次實例化。
    原理:enum是通過繼承了Enum類實現的,Enum類是final的;enum僅有私有構造器,防止外部的額外構造;JVM禁止實現枚舉類型的readObject等方法。*/

    INSTANCE;
    public void otherMethods(){
        System.out.println("Something");
    }
}

4. 工廠模式

  • 就是建立一個工廠類,對實現了同一接口的一些類進行實例的創建。
  • 可以通過反射實現,根據傳入的對象類的類型創建相應對象。

5. 抽象工廠模式

  • 讓工廠類繼承一個接口,增加新功能的時候創建新的工廠類。

6. 建造者模式

  • 工廠類模式提供的是創建單個類的模式,而建造者模式則是將各種產品集中起來進行管理,用來創建複合對象。
  • 一個 Builder 類會一步一步構造最終的對象。
  • 注意事項:與工廠模式的區別是:建造者模式更加關注零件裝配的順序。
  • 一般實現,需要被建造的對象內部有個靜態內部類xxBuilder,通過外部創建Builder對象,調用Builder對象的方法,一步步添加屬性,最後build()方法返回一個對象。

7. 裝飾器模式

  • 何時使用:在不想增加很多子類的情況下擴展類。(實現方法和代理模式有很多重複的)
  • 裝飾器通過包裝一個裝飾對象來擴展其功能,而又不改變其接口,這實際上是基於對象的適配器模式的一種變種。(適配器模式需要實現另外一個接口,而裝飾器模式必須實現該對象的接口。)
  • 實例流程:通過繼承和目標對象一樣接口、創建一個抽象類xxDecorator,該Decorator抽象類包含了一個目標對象,接着和代理模式差不多,再繼承該xxDecorator實現具體的裝飾器,裝飾器中對目標對象的方法進行增強。
  • 在JDK中,常見的作法是在創建一個類型的時候時,同時也傳入同一類型的對象。

8. 適配器模式

  • 適配器模式(Adapter Pattern)是作爲兩個不兼容的接口之間的橋樑,用來把一個接口轉化成另一個接口。
  • 經常的用法,創建一個Adapter類,Adapter分別實現或者繼承A類或者B類的方法,通過A類的方法中調用B類的方法,或者B類的方法中調用A類的方法,來使得不匹配的兩個接口,能夠使用另外一個接口的方法,這就是匹配的含義。

9. 觀察者模式

  • 觀察者訂閱被觀察者的狀態,當被觀察者狀態改變的時候會通知所有訂閱的觀察者的過程。
  • 用法:將被觀察者傳入到觀察者中,然後觀察者調用被觀察者對象的方法進行通知。
  • 和異步操作中的回調很相似,最後都是通過被等待對象調用等待對象的方法來通知。

10. 命令模式

  • 命令模式就是把命令封裝成對象,然後將動作請求者與動作執行者完全解耦。可以通過set方法把命令對象傳入動作執行者類。

11. 模板模式

  • 一個抽象類公開定義了執行它的方法的方式/模板。它的子類可以按需要重寫方法實現,但調用將以抽象類中定義的方式進行。
  • 封裝不變部分,擴展可變部分。 2、提取公共代碼,便於維護。 3、行爲由父類控制,子類實現。
  • 常用作法:在抽象類(父類)中,不可重寫的模板方法定義爲final,然後模板方法裏面調用其他抽象方法,這些抽象方法被子類重寫、擴展。

12. 外觀模式

  • 隱藏系統的複雜性,並向客戶端提供了一個客戶端可以訪問系統的接口。

13. 狀態模式

  • 類的行爲是基於它的狀態改變的。這種類型的設計模式屬於行爲型模式。
  • 在狀態模式中,我們創建表示各種狀態的對象(State)和一個行爲隨着狀態對象改變而改變的 Context 對象。

14.享元模式

  • 主要用於減少創建對象的數量,以減少內存佔用和提高性能。
  • 嘗試重用現有的同類對象,如果未找到匹配的對象,則創建新對象。(可以用 HashMap 存儲這些對象)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章