1. 程式人生 > >14.設計模式、單例模式、介面卡模式

14.設計模式、單例模式、介面卡模式

設計模式
設計模式|菜鳥教程

1.什麼是設計模式(Design Patterns)?你用過哪種設計模式?用在什麼場合
2.你知道哪些商業級設計模式?
3.哪些設計模式可以增加系統的可擴充套件性
4.除了單例模式,你在生產環境中還用過什麼設計模式?
5.寫 Singleton 單例模式
6.單例模式的雙檢鎖是什麼
7.如何建立執行緒安全的 Singleton
8.介面卡模式是什麼?什麼時候使用
9.介面卡模式和代理模式之前有什麼不同
10.介面卡模式和裝飾器模式有什麼區別
11.什麼時候使用享元模式
12.什麼時候使用組合模式
13.什麼時候使用訪問者模式
14.什麼是模板方法模式
15.請給出1個符合開閉原則的設計模式的例子

1.什麼是設計模式(Design Patterns)?你用過哪種設計模式?用在什麼場合
一套被反覆使用、多數人知曉的、經過分類編目的、程式碼 設計經驗 的總結;
使用設計模式是為了 可重用 程式碼、讓程式碼 更容易 被他人理解、保證程式碼 可靠性;
設計模式使程式碼編制  真正工程化;
設計模式使軟體工程的 基石脈絡, 如同大廈的結構一樣;
並不直接用來完成程式碼的編寫,而是 描述 在各種不同情況下,要怎麼解決問題的一種方案;
能使不穩定依賴於相對穩定、具體依賴於相對抽象,避免引起麻煩的緊耦合,以增強軟體設計面對並適應變化的能力。
2.你知道哪些商業級設計模式?
不造咋答。一般用的多的單例、策略、介面卡、命令、建造者工廠
3.哪些設計模式可以增加系統的可擴充套件性
工廠模式
抽象工廠模式
觀察者模式:很方便增加觀察者,方便系統擴充套件
模板方法模式:很方便的實現不穩定的擴充套件點,完成功能的重用
介面卡模式:可以很方便地對適配其他介面
代理模式:可以很方便在原來功能的基礎上增加功能或者邏輯
責任鏈模式:可以很方便得增加攔截器/過濾器實現對資料的處理,比如struts2的責任鏈
策略模式:通過新增策略從而改變原來的執行策略
擴充套件:

1.Load Balancer 負載均衡 分發器根據一定的規則將請求傳送到某個工作示例處理
2.Scatter and Gather 分散聚集模式 分發器將請求分發到執行緒池中多個執行緒,每個執行緒計算本地執行緒結果後發回分發器,分發器合併結果後返回。
3.Result Cache 結果快取 分發器會先查下請求是否已經快取,如果被快取過並且沒過期則直接返回快取中的結果,
4.Shared Space 共享空間 所有工作者執行緒通過共享空間共享資料,共享資料是為了協調各個執行緒的併發和資料分隔任務分隔問題。
5.Pipe and Filter 管道過濾器模式 所有的工作者用管道連線起來,資料流通過管理中的過濾器順序執行
6.MapReduce 使用分散式檔案系統來解決單個磁碟的IO問題
7.Bulk Synchronous Parallel 批量同步並行模式 基於master機器的鎖機制來協調各個工作者執行緒並行執行
8.Execution Orchestrator 執行協調器 任務管理和分發的協調器,用於將任務爭取分發都各個工作者執行緒執行
4.除了單例模式,你在生產環境中還用過什麼設計模式?
策略、介面卡、命令、建造者工廠
5.寫 Singleton 單例模式

1. 懶漢模式

複製程式碼
public class SingletonDemo {
    private static SingletonDemo instance;
    private SingletonDemo(){

    }
    public static SingletonDemo getInstance(){
        if(instance==null){
            instance=new SingletonDemo();
        }
        return instance;
    }
}

2. 執行緒安全的懶漢模式

複製程式碼
public class SingletonDemo {
    private static SingletonDemo instance;
    private SingletonDemo(){

    }
    public static synchronized SingletonDemo getInstance(){
        if(instance==null){
            instance=new SingletonDemo();
        }
        return instance;
    }
}

3. 餓漢模式

複製程式碼
public class SingletonDemo {
    private static SingletonDemo instance=new SingletonDemo();
    private SingletonDemo(){

    }
    public static SingletonDemo getInstance(){
        return instance;
    }
}

4. 靜態類內部載入

複製程式碼
public class SingletonDemo {
    private static class SingletonHolder{
        private static SingletonDemo instance=new SingletonDemo();
    }
    private SingletonDemo(){
        System.out.println("Singleton has loaded");
    }
    public static SingletonDemo getInstance(){
        return SingletonHolder.instance;
    }
}

5. 列舉方法

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

6. 雙重校驗鎖法

複製程式碼
public class SingletonDemo {
    private volatile static SingletonDemo instance;
    private SingletonDemo(){
        System.out.println("Singleton has loaded");
    }
    public static SingletonDemo getInstance(){
        if(instance==null){
            synchronized (SingletonDemo.class){
                if(instance==null){
                    instance=new SingletonDemo();
                }
            }
        }
        return instance;
    }
}

6.單例模式的雙檢鎖是什麼
public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {  //1
      if (instance == null)          //2
        instance = new Singleton();  //3
    }
  }
  return instance;
}

雙重檢查鎖定背後的理論是:在 //2 處的第二次檢查使(如清單 3 中那樣)建立兩個不同的 Singleton 物件成為不可能。假設有下列事件序列:

  1. 執行緒 1 進入 getInstance() 方法。 

  2. 由於 instance 為 null,執行緒 1 在 //1 處進入 synchronized 塊。 

  3. 執行緒 1 被執行緒 2 預佔。

  4. 執行緒 2 進入 getInstance() 方法。

  5. 由於 instance 仍舊為 null,執行緒 2 試圖獲取 //1 處的鎖。然而,由於執行緒 1 持有該鎖,執行緒 2 在 //1 處阻塞。

  6. 執行緒 2 被執行緒 1 預佔。

  7. 執行緒 1 執行,由於在 //2 處例項仍舊為 null,執行緒 1 還建立一個 Singleton 物件並將其引用賦值給 instance

  8. 執行緒 1 退出 synchronized 塊並從 getInstance() 方法返回例項。 

  9. 執行緒 1 被執行緒 2 預佔。

  10. 執行緒 2 獲取 //1 處的鎖並檢查 instance 是否為 null。 

  11. 由於 instance 是非 null 的,並沒有建立第二個 Singleton 物件,由執行緒 1 建立的物件被返回。

雙重檢查鎖定背後的理論是完美的。不幸地是,現實完全不同。雙重檢查鎖定的問題是:並不能保證它會在單處理器或多處理器計算機上順利執行。

雙重檢查鎖定失敗的問題並不歸咎於 JVM 中的實現 bug,而是歸咎於 Java 平臺記憶體模型。記憶體模型允許所謂的“無序寫入”,這也是這些習語失敗的一個主要原因。

7.如何建立執行緒安全的 Singleton

靜態內部類的方式建立單例模式(static inner class)

  1. publicclass Singleton {  
  2.     private Singleton() {  
  3.     }  
  4.     privatestaticclass SingletonHolder {// 靜態內部類
  5.         privatestatic Singleton singleton = new Singleton();  
  6.     }  
  7.     publicstatic Singleton getInstance() {  
  8.         return SingletonHolder.singleton;  
  9.     }  

8.介面卡模式是什麼?什麼時候使用
介面卡(變壓器)模式:把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面原因不匹配而無法一起工作的兩個類能夠一起工作。適配類可以根據引數返還一個合適的例項給客戶端。
VO、DO、DTO、BO之間適配
配器模式主要是在程式程式碼寫好之後 又遇到了需要使用新物件的情況 新的物件和原來使用的物件 本質上是一種 但是裡面的方法和屬性都不相同 所以為了減少程式碼的修改 就像電源介面卡一樣 使用不同的物件的一種方法
9.介面卡模式和代理模式之前有什麼不同        參考連結
介面卡模式是因為新舊介面不一致導致出現了客戶端無法得到滿足的問題,但是,由於舊的介面是不能被完全重構掉的,因為我們還想使用實現了這個介面的一些服務。那麼為了使用以前實現舊介面的服務,我們就應該把新的介面轉換成舊介面;實現這個轉換的類就是抽象意義的轉換器。
就比如在java中早期的列舉介面是Enumeration而後定義的列舉介面是Iterator;有很多舊的類實現了enumeration介面暴露出了一些服務,但是這些服務我們現在想通過傳入Iterator介面而不是Enumeration介面來呼叫,這時就需要一個介面卡,那麼client就能用這個服務了(服務端只想用Iterator或者只知道這個介面)。
相比於介面卡的應用場景,代理就不一樣了,雖然代理也同樣是增加了一層,但是,代理提供的介面和原本的介面是一樣的,代理模式的作用是不把實現直接暴露給client,而是通過代理這個層,代理能夠做一些處理。
10.介面卡模式和裝飾器模式有什麼區別        參考連結
介面卡模式主要是為了介面的轉換,而裝飾者模式關注的是通過組合來動態的為被裝飾者注入新的功能或行為(即所謂的責任)。
介面卡將一個物件包裝起來以改變其介面;裝飾者將一個物件包裝起來以增強新的行為和責任;而外觀將一群物件包裝起來以簡化其介面
11.什麼時候使用享元模式
系統有大量相似物件。 需要緩衝池的場景。
如:JAVA中的 String,如果有則返回,如果沒有則建立一個字串儲存在字串快取池裡面。資料庫的資料池。
12.什麼時候使用組合模式
部分、整體場景,如樹形選單,檔案、資料夾的管理。
如:算術表示式包括運算元、操作符和另一個運算元,其中,另一個操作符也可以是操作樹、操作符和另一個運算元。在JAVA AWT和SWING中對於Button和Checkbox是樹葉Container是樹枝。
13.什麼時候使用訪問者模式
物件結構中物件對應的類很少改變,但經常需要在此物件結構上定義新的操作。需要對一個物件結構中的物件進行很多不同的並且不相關的操作,而需要避免讓這些操作"汙染"這些物件的類,也不希望在增加新操作時修改這些類。
注意事項:訪問者可以對功能進行統一,可以做報表、UI、攔截器與過濾器。
如:您在朋友家做客,您是訪問者,朋友接受您的訪問,您通過朋友的描述,然後對朋友的描述做出一個判斷,這就是訪問者模式。
14.什麼是模板方法模式
意圖:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
主要解決:一些方法通用,卻在每一個子類都重新寫了這一方法。
何時使用:有一些通用的方法。
如何解決:將這些通用演算法抽象出來。
關鍵程式碼:在抽象類實現,其他步驟在子類實現。
應用例項: 1、在造房子的時候,地基、走線、水管都一樣,只有在建築的後期才有加壁櫥加柵欄等差異。 2、西遊記裡面菩薩定好的 81 難,這就是一個頂層的邏輯骨架。 3、spring 中對 Hibernate 的支援,將一些已經定好的方法封裝起來,比如開啟事務、獲取 Session、關閉 Session 等,程式設計師不重複寫那些已經規範好的程式碼,直接丟一個實體就可以儲存。
優點: 1、封裝不變部分,擴充套件可變部分。 2、提取公共程式碼,便於維護。 3、行為由父類控制,子類實現。
缺點:每一個不同的實現都需要一個子類來實現,導致類的個數增加,使得系統更加龐大。
使用場景: 1、有多個子類共有的方法,且邏輯相同。 2、重要的、複雜的方法,可以考慮作為模板方法。
注意事項:為防止惡意操作,一般模板方法都加上 final 關鍵詞。
15.請給出1個符合開閉原則的設計模式的例子        參考連結
對擴充套件開放、對修改關閉
策略模式、簡單工廠、工廠方法、抽象工廠、建造者模式、橋樑模式、外觀模式、中介模式、迭代子模式