主頁 > 軟體設計 > 每天學習一個設計模式(一):結構型之配接器模式

每天學習一個設計模式(一):結構型之配接器模式

2020-09-12 00:24:57 軟體設計

一、基本概念

配接器模式是將某個類的介面轉換成客戶端期望的另一個介面表示,目的是消除由于介面不匹配所造成的的類的兼容性問題,

二、通俗解釋

ADAPTER 配接器模式:在朋友聚會上碰到了一個美女Sarah,從香港來的,可我不會說粵語,她不會說普通話,只好求助于我的朋友kent了,他作為我和Sarah之間的Adapter,讓我和Sarah可以相互交談了(也不知道他會不會耍我) 配接器(變壓器)模式:把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面原因不匹配而無法一起作業的兩個類能夠一起作業,適配類可以根據引數返還一個合適的實體給客戶端,

用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極、陰極外,還有一個地極,而有些地方的電源插座卻只有兩極,沒有地極,電源插座與筆記本電腦的電源插頭不匹配使得筆記本電腦無法使用,這時候一個三相到兩相的轉換器(配接器)就能解決此問題,而這正像是本模式所做的事情,

三、分類

主要分三類:類的配接器模式、物件的配接器模式、介面的配接器模式,

1. 類的配接器模式:

class Source {
    public void method1() {
        System.out.println("This is original method...");
    }
}

interface Targetable {

    /**
     * 與原類中的方法相同
     */
    public void method1();

    /**
     * 新類的方法
     */
    public void method2();
}

class Adapter extends Source implements Targetable {

    @Override
    public void method2() {
        System.out.println("This is the targetable method...");
    }
}

public class AdapterPattern {
    public static void main(String[] args) {
        Targetable targetable = new Adapter();
        targetable.method1();
        targetable.method2();
    }
}

2. 物件的配接器模式

基本思路和類的配接器模式相同,只是將Adapter 類作修改,這次不繼承Source 類,而是持有Source 類的實體,以達到解決兼容性的問題,

class Source {
    public void method1() {
        System.out.println("This is original method...");
    }
}

interface Targetable {

    /**
     * 與原類中的方法相同
     */
    public void method1();

    /**
     * 新類的方法
     */
    public void method2();
}

class Wrapper implements Targetable {

    private Source source;

    public Wrapper(Source source) {
        super();
        this.source = source;
    }

    @Override
    public void method1() {
        source.method1();
    }

    @Override
    public void method2() {
        System.out.println("This is the targetable method...");
    }
}

public class AdapterPattern {
    public static void main(String[] args) {
        Source source = new Source();
        Targetable targetable = new Wrapper(source);
        targetable.method1();
        targetable.method2();
    }
}

3. 介面的配接器模式


介面的配接器是這樣的:有時我們寫的一個介面中有多個抽象方法,當我們寫該介面的實作類時,必須實作該介面的所有方法,這明顯有時比較浪費,因為并不是所有的方法都是我們需要的,有時只需要某一些,此處為了解決這個問題,我們引入了介面的配接器模式,借助于一個抽象類,該抽象類實作了該介面,實作了所有的方法,而我們不和原始的介面打交道,只和該抽象類取得聯系,所以我們寫一個類,繼承該抽象類,重寫我們需要的方法就行,

/**
 * 定義埠介面,提供通信服務
 */
interface Port {
    /**
     * 遠程SSH埠為22
     */
    void SSH();

    /**
     * 網路埠為80
     */
    void NET();

    /**
     * Tomcat容器埠為8080
     */
    void Tomcat();

    /**
     * MySQL資料庫埠為3306
     */
    void MySQL();
}

/**
 * 定義抽象類實作埠介面,但是什么事情都不做
 */
abstract class Wrapper implements Port {
    @Override
    public void SSH() {

    }

    @Override
    public void NET() {

    }

    @Override
    public void Tomcat() {

    }

    @Override
    public void MySQL() {

    }
}

/**
 * 提供聊天服務
 * 需要網路功能
 */
class Chat extends Wrapper {
    @Override
    public void NET() {
        System.out.println("Hello World...");
    }
}

/**
 * 網站服務器
 * 需要Tomcat容器,Mysql資料庫,網路服務,遠程服務
 */
class Server extends Wrapper {
    @Override
    public void SSH() {
        System.out.println("Connect success...");
    }

    @Override
    public void NET() {
        System.out.println("WWW...");
    }

    @Override
    public void Tomcat() {
        System.out.println("Tomcat is running...");
    }

    @Override
    public void MySQL() {
        System.out.println("MySQL is running...");
    }
}

public class AdapterPattern {

    private static Port chatPort = new Chat();
    private static Port serverPort = new Server();

    public static void main(String[] args) {
        // 聊天服務
        chatPort.NET();

        // 服務器
        serverPort.SSH();
        serverPort.NET();
        serverPort.Tomcat();
        serverPort.MySQL();
    }
}

介面的配接器模式又稱為預設配接器模式

  預設適配(Default Adapter)模式為一個介面提供預設實作,這樣子型別可以從這個預設實作進行擴展,而不必從原有介面進行擴展,作為配接器模式的一個特例,預設是適配模式在JAVA語言中有著特殊的應用,

魯智深的故事

  和尚要做什么呢?吃齋、念經、打坐、撞鐘、習武等,如果設計一個和尚介面,給出所有的和尚都需要實作的方法,那么這個介面應當如下:

public interface 和尚 {
    public void 吃齋();
    public void 念經();
    public void 打坐();
    public void 撞鐘();
    public void 習武();
    public String getName();
}

顯然,所有的和尚類都應當實作介面所定義的全部方法,不然就根本通不過JAVA語言編輯器,像下面的魯智深類就不行,

public class 魯智深 implements 和尚{
    public void 習武(){
        拳打鎮關西;
        大鬧五臺山;
        大鬧桃花村;
        火燒瓦官寺;
        倒拔垂楊柳;
    }
    public String getName(){
        return "魯智深";
    }
}

由于魯智深只實作了getName()和習武()方法,而沒有實作任何其他的方法,因此,它根本就通不過Java語言編譯器,魯智深類只有實作和尚介面的所有的方法才可以通過Java語言編譯器,但是這樣一來魯智深就不再是魯智深了,以史為鑒,可以知天下,研究一下幾百年前魯智深是怎么剃度成和尚的,會對Java編程有很大的啟發,不錯,當初魯達剃度,眾僧說:“此人形容丑惡、相貌兇頑,不可剃度他",但是長老卻說:”此人上應天星、心地剛直,雖然時下兇頑,命中駁雜,久后卻得清凈,證果非凡,汝等皆不及他,”

  原來如此!看來只要這里也應上一個天星的話,問題就解決了!使用面向物件的語言來說,“應”者,實作也;“天星”者,抽象類也,

public abstract class 天星 implements 和尚 {
    public void 吃齋(){}
    public void 念經(){}
    public void 打坐(){}
    public void 撞鐘(){}
    public void 習武(){}
    public String getName(){
        return null;
    }
}

魯智深類繼承抽象類“天星”

public class 魯智深 extends 和尚{
    public void 習武(){
        拳打鎮關西;
        大鬧五臺山;
        大鬧桃花村;
        火燒瓦官寺;
        倒拔垂楊柳;
    }
    public String getName(){
        return "魯智深";
    }
}

這個抽象的天星類便是一個配接器類,魯智深實際上借助于配接器模式達到了剃度的目的,此配接器類實作了和尚介面所要求的所有方法,但是與通常的配接器模式不同的是,此配接器類給出的所有的方法的實作都是“平庸”的,這種“平庸化”的配接器模式稱作預設適配模式,

  在很多情況下,必須讓一個具體類實作某一個介面,但是這個類又用不到介面所規定的所有的方法,通常的處理方法是,這個具體類要實作所有的方法,那些有用的方法要有實作,那些沒有用的方法也要有空的、平庸的實作,

  這些空的方法是一種浪費,有時也是一種混亂,除非看過這些空方法的代碼,程式員可能會以為這些方法不是空的,即便他知道其中有一些方法是空的,也不一定知道哪些方法是空的,哪些方法不是空的,除非看過這些方法的源代碼或是檔案,

  預設適配模式可以很好的處理這一情況,可以設計一個抽象的配接器類實作介面,此抽象類要給介面所要求的每一種方法都提供一個空的方法,就像幫助了魯智深的“上應天星”一樣,此抽象類可以使它的具體子類免于被迫實作空的方法,

四、類配接器和物件配接器的權衡

  • 類配接器使用物件繼承的方式,是靜態的定義方式;而物件配接器使用物件組合的方式,是動態組合的方式,
  • 對于類配接器由于配接器直接繼承了Adaptee,使得配接器不能和Adaptee的子類一起作業,因為繼承是靜態的關系,當配接器繼承了Adaptee后,就不可能再去處理  Adaptee的子類了,

  • 對于物件配接器一個配接器可以把多種不同的源適配到同一個目標,換言之,同一個配接器可以把源類和它的子類都適配到目標介面,因為物件配接器采用的是物件組合的關系,只要物件型別正確,是不是子類都無所謂,

  • 對于類配接器配接器可以重定義Adaptee的部分行為,相當于子類覆寫父類的部分實作方法,

  • 對于物件配接器要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類來實作重定義,然后讓配接器組合子類,雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時適用于所有的源,

  • 對于類配接器,僅僅引入了一個物件,并不需要額外的參考來間接得到Adaptee,

  • 對于物件配接器,需要額外的參考來間接得到Adaptee,

建議盡量使用物件配接器的實作方式,多用合成或聚合、少用繼承,當然,具體問題具體分析,根據需要來選用實作方式,最適合的才是最好的,

配接器模式的優點

  • 更好的復用性:系統需要使用現有的類,而此類的介面不符合系統的需要,那么通過配接器模式就可以讓這些功能得到更好的復用,

  • 更好的擴展性:在實作配接器功能的時候,可以呼叫自己開發的功能,從而自然地擴展系統的功能,

配接器模式的缺點

  過多的使用配接器,會讓系統非常零亂,不易整體進行把握,比如,明明看到呼叫的是A介面,其實內部被適配成了B介面的實作,一個系統如果太多出現這種情況,無異于一場災難,因此如果不是很有必要,可以不使用配接器,而是直接對系統進行重構,

配接器模式的用意是要改變源的介面,以便于目標介面相容,預設適配的用意稍有不同,它是為了方便建立一個不平庸的配接器類而提供的一種平庸實作,

  在任何時候,如果不準備實作一個介面的所有方法時,就可以使用“預設適配模式”制造一個抽象類,給出所有方法的平庸的具體實作,這樣,從這個抽象類再繼承下去的子類就不必實作所有的方法了,


(參考:《JAVA與模式》之配接器模式、Java 中幾種常用設計模式、java常用的設計模式)

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/8568.html

標籤:設計模式

上一篇:單例模式

下一篇:每天學習一個設計模式(二):結構型之橋梁模式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more