設計模式-適配器(Adapter)

来源:http://www.cnblogs.com/bateman6988/archive/2017/11/12/7820152.html
-Advertisement-
Play Games

一、概念 將一個類的介面轉換成客戶希望的另外一個介面,適配器模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。 二、模式動機 適配器的本質就是轉換類型(源介面的功能和目標介面的功能相同或者相近,如此轉換才有意義),目的就是復用已有的功能。 三、模式的結構 適配器跟據實現方式可以分為類適配 ...


一、概念

  將一個類的介面轉換成客戶希望的另外一個介面,適配器模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。  

二、模式動機

  適配器的本質就是轉換類型(源介面的功能和目標介面的功能相同或者相近,如此轉換才有意義),目的就是復用已有的功能。

三、模式的結構

  適配器跟據實現方式可以分為類適配器和對像適配器,簡單結構圖如下:

    

                                        (類適配器)                                                                                           (對象適配器)

 

     類適配器:

    1.Target:期待得到的目標介面,由於是類適配器,所以這個必須是Interface 

    2.Adaptee:被適配的介面,是一個具體類

    3.Adapter:適配器,具體類

              類適配器的實現思路是,通過繼承被適配器的類Adaptee,實現目標介面Target。由於繼承是靜態關係,所以他只能適配當前的類Adaptee,而不能適配Adaptee的其它子類。由於是繼承關係,適配器類可以很方便的重寫被適配器類中的方法。

    

   類適配器的樣例代碼如下:

package adapter.classpattern;

/**
 * 期望的目標介面
* @ClassName: Target 
* @author beteman6988
* @date 2017年11月11日 下午11:20:44 
*
 */
public interface Target {
    
    /**
     * 源類也有的方法
    * @Title: sampleOperation1 
    * @param    
    * @return void    
    * @throws
     */
    public void sampleOperation1();
    
    /**
     * 源類中沒有的方法
    * @Title: sampleOperation2 
    * @param    
    * @return void    
    * @throws
     */
    public void sampleOperation2();

}
package adapter.classpattern;

/**
 * 被適配的類
* @ClassName: Adaptee 
* @author beteman6988
* @date 2017年11月11日 下午11:23:22 
*
 */
public class Adaptee {
    
    public void sampleOperation1() {
        //Do  something......
    }

}
package adapter.classpattern;

public class Adapter extends Adaptee implements Target {

    /**
     * 目標介面需要,但是源類中沒有的方法,需自已恰當的實現
     */
    @Override
    public void sampleOperation2() {
        // TODO Auto-generated method stub
    }

}

 

   對象適配器:

    1.Target:期待得到的目標介面,可以是具體類或者抽象類

    2.Adaptee:被適配的介面

    3.Adapter:適配器,具體類

   對象適配器的實現思路是:適配器類(Adapter)繼承或實現目標介面(Target),適配器類含有被適配器介面的對象成員, 適配器類通過委派,調用被適配對象的方法以實現復用,達到實現目標介面到源介面(被適配器介面)的轉換。

    對象適配器,由於引用的是被適配介面的對象,所以他可以適配被適配介面的所有子類或者實現,但是無法覆蓋被適配介面的方法,只能適過一個子類繼承適配器介面,改寫父類的方法,然後適配器類適配這個子類的方法來實現。

   

   樣例代碼如下:

package adapter.objpattern;

/**
 * 期望的目標介面
* @ClassName: Target 
* @author beteman6988
* @date 2017年11月11日 下午11:20:44 
*
 */
public interface Target {
    
    /**
     * 目標介面的方法
    * @Title: sampleOperation1 
    * @param    
    * @return void    
    * @throws
     */
    public void sampleOperation1();
    
    /**
     * 目標介面的方法
    * @Title: sampleOperation2 
    * @param    
    * @return void    
    * @throws
     */
    public void sampleOperation2();

}
package adapter.objpattern;

/**
 * 被適配的類
* @ClassName: Adaptee 
* @author beteman6988
* @date 2017年11月11日 下午11:23:22 
*
 */
public class Adaptee {
    
    public void sampleOperationA() {
        System.out.println("適配到-Adaptee.sampleOperationA()");
    }

}
package adapter.objpattern;

public class Adapter extends Adaptee implements Target {
    
    private Adaptee adaptee;
    
    public Adapter(Adaptee adaptee) {
        this.adaptee=adaptee;
    }

    /**
     * 目標介面需要的方法
     */
    @Override
    public void sampleOperation1() {
        /**
         * 通過委派復用被適配對象的方法
         */
        this.adaptee.sampleOperationA();
    }
    
    /**
     * 目標介面需要,但被適配對象不中具備的方法
     */
    @Override
    public void sampleOperation2() {
        //DO  Something......
        System.out.println("目標介面需要,但被適配對象中不具備的方法,需恰當的實現。。。。。。");
    }
}
package adapter.objpattern;

public class Client {
    public static void main(String[] args) {
        Adaptee adaptee=new Adaptee();  //被適配的源對象
        Target target=new Adapter(adaptee); //將源對象適配到目標介面的適配器
        target.sampleOperation1(); //目標介面調用自已的方法,以期待源對象來實現。
        target.sampleOperation2();
    }
}

  運行結果如下:

  適配到-Adaptee.sampleOperationA()
  目標介面需要,但被適配對象中不具備的方法,需恰當的實現。。。。。。

四、預設適配器

  預設適配器就是用一個抽像類繼承或實現目標介面,對目標介面中的所有方法提供平庸實現,從該抽象類繼承的子類,只需要覆寫父類中所需要關註的方法。而不需要實現目標介面的所有方法。比如一個按鈕事件的介面,所有按鈕都支持單擊和雙擊事件,但是現在有一個按鈕只需要對單擊事件做出響應,這時這個按鈕就和目標期待的介面不匹配,如果要匹配目標介面,這個按鈕事件對象就必須對雙擊事件也要做出響應,用預設適配器方法就能很好解決這個問題。首先為這個按鈕事件介面提供一個抽象類,抽象類平庸實現(什麼事都不做)對單擊和雙擊事件的響應,然後只支持單擊事件響應的按鈕繼承於這個抽象類即可,然後只需重寫抽象類中的單擊按鈕響應方法即可。

五、模式樣例

   就以日常電視的電源插座為位,目前只有一個二孔的插座,而電視插頭是三插頭,如何讓電視的三孔插頭插到兩孔的插座上,使電視能正常工作,就需要一個兩空到三空的轉換插座,即就是本例中的轉換器Adapter,下麵以程式的方式說明整個轉換過程。

  類模式:

   

  兩孔到三孔的插座轉換器繼承於兩孔插座,表示TwoToThreeSocketAdapter是特殊的TwoProngedSocket,他具有TwoProngedSocket的兩個極(正極和負極)的功能,且多了一個地極,代碼如下:

  

package adapter.classpattern.sample;

/**
 * 兩孔插座
* @ClassName: TwoProngedSocket 
* @author beteman6988
* @date 2017年11月12日 下午9:32:40 
*
 */
public class TwoProngedSocket {
    
    /**
     * 負極插空
    * @Title: requestNegativePole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestNegativePole() {
        System.out.println("兩孔插座的負極插空開始工作。。。。。。");
    }

    /**
     * 正極插空
    * @Title: requestPositivePole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestPositivePole() {
        System.out.println("兩孔插座的正極插空。。。。。。");
    }
}
package adapter.classpattern.sample;

/**
 * 電視機需要的三插孔插座介面
* @ClassName: ThreeProngedSocket 
* @author beteman6988
* @date 2017年11月12日 下午9:37:58 
*
 */
public interface ThreeProngedSocket {
    
    /**
     * 負極插孔
    * @Title: requestNegativePole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestNegativePole();

    /**
     * 正極插孔
    * @Title: requestPositivePole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestPositivePole();

    /**
     * 地極插孔
    * @Title: requestEarthPole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestEarthPole();

}
package adapter.classpattern.sample;
 
/**
 * 兩孔到三孔的插座轉換器,對外是三孔插座(implements ThreeProngedSocket)或者說具備了三孔插座的功能,
 * 卻是一個特殊的兩孔插座(extends TwoProngedSocket)
* @ClassName: TwoToThreeSocketAdapter 
* @author beteman6988
* @date 2017年11月12日 下午9:47:01 
*
 */
public class TwoToThreeSocketAdapter extends TwoProngedSocket  implements ThreeProngedSocket{

    /**
     * 兩孔插座不具備的第三極 地極接地
     */
    @Override
    public void requestEarthPole() {
        System.out.println("地極插空接地開始工作。。。。。。");
    }

}
package adapter.classpattern.sample;

/**
 * 電視類,具備播放功能
* @ClassName: TV 
* @author beteman6988
* @date 2017年11月12日 下午10:00:15 
*
 */
public class TV {
    
    /**
     * 電視播放時,需要一個三孔插坐,或者具備三孔插座功能(implements ThreeProngedSocket)的插座
    * @Title: play 
    * @param @param socket   
    * @return void    
    * @throws
     */
    public void play(ThreeProngedSocket socket) {
        socket.requestNegativePole(); //負極能正常工作
        socket.requestPositivePole(); //正極能正常工作
        socket.requestEarthPole();    //地極能正常工作
        System.out.println("電視正在播放。。。。。");
    }
    
    public static void main(String[] args) {
        TV  tv=new TV();
        
        //目前房間只有一個兩孔插座,和一個兩孔到三孔的插座轉的換器,那麼轉換器插到兩孔插座上,上面的三孔插座即可供電視機用。
        ThreeProngedSocket socket=new TwoToThreeSocketAdapter();
        
        //給電視提供一個具有三孔插座功能的轉換器
        tv.play(socket);
    }
}

  運行結果如下:

  兩孔插座的負極插空開始工作。。。。。。

    兩孔插座的正極插空。。。。。。

  地極插空接地開始工作。。。。。。
  電視正在播放。。。。。

 

  對像模式:

  三孔插座轉換器想具備對外提供電力的功能,必須給他提供一個真實的兩孔插座對象,當對他請求正負極時,通過委派給真實的兩孔插座的正負極對外提供電力。

  

package adapter.objpattern.sample;

/**
 * 兩孔插座
* @ClassName: TwoProngedSocket 
* @author beteman6988
* @date 2017年11月12日 下午9:32:40 
*
 */
public class TwoProngedSocket {
    
    /**
     * 負極插孔
    * @Title: requestNegativePole 
    * @param    
    * @return void    
    * @throws
     */
    public String requestNegativePole() {
        return "兩孔插座的負極插空開始工作。。。。。。";
    }

    /**
     * 正極插孔
    * @Title: requestPositivePole 
    * @param    
    * @return void    
    * @throws
     */
    public String requestPositivePole() {
        return "兩孔插座的正極插空。。。。。。" ;
    }
}
package adapter.objpattern.sample;

/**
 * 電視機需要的三插空插座介面
* @ClassName: ThreeProngedSocket 
* @author beteman6988
* @date 2017年11月12日 下午9:37:58 
*
 */
public interface ThreeProngedSocket {
    
    /**
     * 負極插孔
    * @Title: requestNegativePole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestNegativePole();

    /**
     * 正極插孔
    * @Title: requestPositivePole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestPositivePole();

    /**
     * 地極插孔
    * @Title: requestEarthPole 
    * @param    
    * @return void    
    * @throws
     */
    public void requestEarthPole();

}
package adapter.objpattern.sample;
 
/**
 * 兩孔到三孔的插座轉換器,對外是三孔插座(implements ThreeProngedSocket)或者說具備了三孔插座的功能,
 * 但是他如果真實具備三孔插作的功能對外提供電力,則必須給他提供一個具有電力的兩孔插作(TwoProngedSocket)對象
 * 他的正負極通過委派這個兩孔插座對象的正負極對外提供電力,地極則自已實現接地
* @ClassName: TwoToThreeSocketAdapter 
* @author beteman6988
* @date 2017年11月12日 下午9:47:01 
*
 */
public class TwoToThreeSocketAdapter    implements ThreeProngedSocket{
    
    //具有電力功能的兩孔插座
    private TwoProngedSocket  twoProngedSocket;
    
    /**
     * 給三也插座轉換器提供具有電力功能的兩孔插座
     * @param twoProngedSocket
     */
    public TwoToThreeSocketAdapter(TwoProngedSocket twoProngedSocket) {
        this.twoProngedSocket=twoProngedSocket;
    }
    /**
     * 兩孔插座不具備的第三極 地極接地
     */
    @Override
    public void requestEarthPole() {
        System.out.println("地極插空接地開始工作。。。。。。");
    }

    @Override
    public void requestNegativePole() {
        System.out.println("委派"+twoProngedSocket.requestNegativePole());
        
    }

    @Override
    public void requestPositivePole() {
        System.out.println("委派"+twoProngedSocket.requestPositivePole());
        
    }

}
package adapter.objpattern.sample;

/**
 * 電視類,具備播放功能
* @ClassName: TV 
* @author beteman6988
* @date 2017年11月12日 下午10:00:15 
*
 */
public class TV {
    
    /**
     * 電視播放時,需要一個三孔插坐,或者具備三孔插座功能(implements ThreeProngedSocket)的插座
    * @Title: play 
    * @param @param socket   
    * @return void    
    * @throws
     */
    public void play(ThreeProngedSocket socket) {
        socket.requestNegativePole(); //負極能正常工作
        socket.requestPositivePole(); //正極能正常工作
        socket.requestEarthPole();    //地極能正常工作
        System.out.println("電視正在播放。。。。。");
    }
    
    public static void main(String[] args) {
        TV  tv=new TV();
        
        //兩孔插座
        TwoProngedSocket twoProngedSocket=new TwoProngedSocket();
        //給三空插座轉換器提供一個兩孔插座,讓他具備三孔插座的功能
        ThreeProngedSocket socket=new TwoToThreeSocketAdapter(twoProngedSocket);
        
        //給電視提供一個具有三孔插座功能的轉換器
        tv.play(socket);
    }
}

  運行結果如下:

  委派兩孔插座的負極插空開始工作。。。。。。

  委派兩孔插座的正極插空。。。。。。

  地極插空接地開始工作。。。。。。

  電視正在播放。。。。。

 六、模式優缺點

   優點:更好的復用性,如果已存的類功能已經有了,只是與目標介面不相容,通過使用適配器,就可以讓已有的功能得到更好的復用。

  缺點:過多的使用適配器,會讓系統非常的凌亂,不易整體把握。如果可行的話,不如直接引用目標對象。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • druapl 的核心可能會有漏洞,這時就需要我們去打補丁。很多補丁都已經有人寫好了,我這裡講的就是如何去打這些已經寫好的補丁。 對於這個問題:drupal8 核心有bug導致了兩個相同的錯誤提示的出現 1.打開項目最外層中的composer.json文件 2.確保 "enable-patching" ...
  • 1.查找文件find / -name filename.txt 根據名稱查找/目錄下的filename.txt文件。find . -name “*.xml” 遞歸查找所有的xml文件2.查看一個程式是否運行ps –ef|grep tomcat 查看所有有關tomcat的進程3.終止線程kill -9 ...
  • 在項目開發裡面,我遇到了這麼一個需求,就是對於node的title欄位,編輯內容的角色不允許對title進行編輯。title欄位是創建內容類型時自動生成的欄位,不能在drupal8後臺直接配置許可權,所以我需要用代碼自定義一個許可權。 1.在/modules/custom下自定義一個模塊,我的模塊名為o ...
  • Hadoop生態大數據系統分為Yam、 HDFS、MapReduce計算框架。TensorFlow分散式相當於MapReduce計算框架,Kubernetes相當於Yam調度系統。TensorFlowOnSpark,利用遠程直接記憶體訪問(Remote Direct Memory Access,RDM ...
  • PHP5以上提供了一個simpleXML對象來操作XML,把XML的節點轉換成對象和數組去操作。 ...
  • 在學習bootstrap的路上,需要使用roots主題,而roots是屬於wordpress的一個主題,那也開始了wordpress的探索~ 首先,使用wordpress我們需要一個必要的環境:PHP+Apache+Mysql。這裡我用的是集成環境,沒必要非獨立安裝。根據自己的操作系統自行下載即可~ ...
  • 1、初步認識 觀察者模式的定義: 在對象之間定義了一對多的依賴,這樣一來,當一個對象改變狀態,依賴它的對象會收到通知並自動更新。 大白話: 其實就是發佈訂閱模式,發佈者發佈信息,訂閱者獲取信息,訂閱了就能收到信息,沒訂閱就收不到信息。 2、這個模式的結構圖 3、可以看到,該模式包含四個角色 抽象被觀 ...
  • 【為了方便獨立成文,原諒在內容排版上的一點點個人強迫症】 【本文內容由上一篇擴展論述(詳見:商城系統下單庫存管控系列雜記(一) http://www.cnblogs.com/bsfz/p/7801980.html)】 四、闡述關於併發環境中庫存管控的一些案例問題,以及涉及到的相關技術實現細節 ... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...