Java面試題之設計模式

單例模式:

定義:

確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例

簡單來說就是這個類只能有一個實例,必須自己創建自己的唯一實例,必須給其它所有對象提供這一實例

適用場景:

在一個系統內,要求一個類有且僅有一個對象

優點:

減少了內存,避免了對資源的多重佔用,對於創建比較繁瑣的對象,只生成一個實例,減少了系統的性能開銷

缺點:

單例模式一般沒有接口,擴展困難

實現:

1).餓漢式單例(立即加載)

public class Danli {
    private Danli(){

    }
    private static Danli danli=new Danli();

    public static Danli getInstance(){
        return danli;
    }
}

單例類通過將構造方法設置爲private避免類在外部被實例化,其他類只能通過getInstance()方法訪問到這個唯一實例

餓漢式單例在類加載初始化時就創建好一個靜態的對象供外部使用,這個對象不會改變,所以本身就是線程安全的

2).懶漢式單例(延遲加載方式)

public class Danli {
    private Danli(){

    }
    private static Danli danli=null;
    public static Danli getInstance(){
        if(danli==null){
            danli=new Danli();
        }
        return danli;
    }
}

該寫法在多線程模式下會產生多個danli對象,應該對在多線程環境下的懶漢式單例就行改進

public class Danli {
    private Danli() {

    }
    private static Danli danli = null;

    public static Danli getInstance() {
        if (danli == null) {
            synchronized (Danli.class) {
                if(danli==null) {
                    danli = new Danli();
                }
            }
        }
            return danli;
        } 
    }

在方法上加synchronized同步鎖解決了多線程環境下多個實例對象的問題,但是運行效率低下,下一個線程想要獲取對象,就必須等待上一個線程釋放鎖以後,所以使用雙重檢查進一步優化,可以避免整個方法被鎖,可以提高執行效率

雙重檢查懶加載的問題:在Java指令中創建對象和賦值操作是分開進行的,即danli=new Danli()語句分兩步執行,但JVM不能保證這兩個操作的先後順序,可能JVM會爲新的Danli實例分配空間,然後直接賦值給Instance成員,然後再去初始化這個Danli實例,這樣當其它線程訪問到Danli實例時,因爲沒有初始化就會報錯

針對上邊的問題,可以使用Volatile來禁止重排序,但是在JDK1.5之前Volatile不能解決重排序問題,在此之前可以採取靜態內部類的方法實現

3).靜態內部類實現

public class Danli{
    private Danli(){
        
    }
    //靜態內部類
    private static class Inner{
        private static Danli danli=new Danli();
    }
    public static Danli getInstance(){
        return Inner.danli;
    }
}

靜態內部類雖然保證了單例模式在多線程下的線程安全,但是在遇到序列化對象時,默認的方式運行得到的結果就是多例的

4).static靜態代碼塊實現

public class Danli{
    private Danli(){
        
    }
    
    private static Danli danli=null;
    
    //靜態代碼塊
    static{
        danli=new Danli();
    }
    
    public static Danli getInstance(){
        return danli;
    }
}

5).內部枚舉類實現

public class SingletonFactory {
    
    // 內部枚舉類
    private enum EnmuSingleton{
        Singleton;
        private Singleton8 singleton;
        
        //枚舉類的構造方法在類加載是被實例化 
        private EnmuSingleton(){
            singleton = new Singleton8();
        }
        public Singleton8 getInstance(){
            return singleton;
        }
    }
    public static Singleton8 getInstance() {
        return EnmuSingleton.Singleton.getInstance();
    }
}

class Singleton8{
    public Singleton8(){}
}

工廠方法模式:

定義:

定義一個用於創建對象的接口,讓子類決定實例化哪一個類,工廠方法將一個類的實例化延遲到子類

適用場景:

有大量產品需要創建,並且具有共同的接口時,可以通過工廠方法模式進行創建

簡單工廠模式:

 

 

抽象工廠方法:

 

 

裝飾模式:

定義:

動態的給一個對象添加一些新的功能,要求裝飾對象和被裝飾對象實現同一個接口,裝飾對象持有被裝飾對象的實例

簡單理解就是,這裏有有3個類,人類,男人類,女人類,人類是父類,男人類和女人類是子類,如果使用繼承這裏就多了2個類,但是用裝飾模式,可以直接將人類裝飾城男人類或者女人類,不用進行繼承,降低了類與類之間的耦合

適用場景:

需要擴展一個類的功能,需要動態的給一個對象增加一個功能,這些功能可以再動態撤銷

缺點:

產生過多相似的對象,不容易排查錯誤

觀察者模式:

定義:

定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則所有依賴它的對象都會得到通知並自動更新

適用場景:

需要遍歷集合中的對象

外觀模式:

 

 

 

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