天天看點

從零開始學設計模式(六)—擴充卡模式(Adapter Pattern)

擴充卡模式

此模式難度系數為初級,由Gang Of Four提出。

擴充卡模式是作為兩個不相容的接口之間的橋梁,這種類型的設計模式屬于結構型模式,它結合了兩個獨立接口的功能。

這種模式涉及到一個單一的類,該類負責加入獨立的或不相容的接口功能。

此模式一般應用于已經存在的類接口中,有動機地修改一個正常運作的系統的接口,這時應該考慮使用擴充卡模式。

意圖

将一個類的接口轉換成客戶希望的另外一個接口。擴充卡模式使得原本由于接口不相容而不能一起工作的那些類可以一起工作。

主要解決:主要解決在軟體系統中,常常要将一些"現存的對象"放到新的環境中,而新環境要求的接口是現對象不能滿足的。

何時使用:

1、系統需要使用現有的類,而此類的接口不符合系統的需要。

2、想要建立一個可以重複使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能在将來引進的類一起工作,這些源類不一定有一緻的接口。

3、通過接口轉換,将一個類插入另一個類系中。(比如老虎和飛禽,現在多了一個飛虎,在不增加實體的需求下,增加一個擴充卡,在裡面包容一個虎對象,實作飛的接口。)

如何解決:繼承或依賴(推薦)。

關鍵代碼:擴充卡繼承或依賴已有的對象,實作想要的目标接口

解釋

現實世界中的例子

讀卡器作為記憶體SD卡和電腦之間的擴充卡,你将記憶體SD卡插入讀卡器,再将讀卡器插入電腦USB接口,這樣電腦可以通過讀卡器來讀取SD卡中的資料

另一個例子是著名的電源擴充卡;三腳插頭不能連接配接到雙管插座,它需要使用一個電源擴充卡,使其與雙管插座相容。還有一個例子是翻譯人員将一個人所說的話翻譯成另一個人所說的話

簡而言之

擴充卡模式允許你在擴充卡中包裝一個不相容的對象,使其與另一個類相容

維基百科

>In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code(在軟體工程中,擴充卡模式是一種軟體設計模式,允許現有類的接口用作另一個接口。它通常用于使現有類與其他類一起工作,而不修改它們的源代碼)           

程式示例

考慮一個隻能使用劃艇而根本不能航行的船長。

首先我們有一個接口劃艇RowingBoat和漁船FishingBoat

/**
 * The interface expected by the client.<br>
 * A rowing boat is rowed to move.
 *
 */
public interface RowingBoat {

  void row();

}
/**
 *
 * Device class (adaptee in the pattern). We want to reuse this class.
 * Fishing boat moves by sailing.
 *
 */
public class FishingBoat {

  private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);

  public void sail() {
    LOGGER.info("The fishing boat is sailing");
  }

}           

接下來定義Captain船長類,船長Uses RowingBoat

/**
 * The Captain uses {@link RowingBoat} to sail. <br>
 * This is the client in the pattern.
 */
public class Captain {

  private RowingBoat rowingBoat;

  public Captain() {}

  public Captain(RowingBoat rowingBoat) {
    this.rowingBoat = rowingBoat;
  }

  public void setRowingBoat(RowingBoat rowingBoat) {
    this.rowingBoat = rowingBoat;
  }
 
  public void row() {
    rowingBoat.row();
  }

}           

現在,假設海盜來了,我們的船長需要逃跑,但是隻有漁船可用。我們需要創造一個擴充卡,讓船長能夠用他的劃艇技能操作漁船

/**
 *
 * Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link RowingBoat}
 * interface expected by the client ({@link Captain}).
 *
 */
public class FishingBoatAdapter implements RowingBoat {

  private FishingBoat boat;

  public FishingBoatAdapter() {
    boat = new FishingBoat();
  }

  @Override
  public void row() {
    boat.sail();
  }
}           

最後”船長“使用漁船逃脫了海盜的追擊

public class App {

  /**
   * Program entry point.
   *
   * @param args command line args
   */
  public static void main(String[] args) {
    // The captain can only operate rowing boats but with adapter he is able to use fishing boats as well
    Captain captain = new Captain(new FishingBoatAdapter());
    captain.row();
  }
}           

結果

被适配的對象和類擴充卡有不同的結果取舍。

類擴充卡:

  • 通過送出一個具體的擴充卡類使适配對象适應目标。是以,當我們想要調整一個适配對象類及其所有子類時,類擴充卡将不起作用
  • 隻引入一個對象,不需要額外的指針間接指向适配對象。
  • 讓擴充卡重寫适配對象的一些方法,因為擴充卡是适配對象的子類。

适配對象:

  • 允許我們用一個擴充卡來處理許多适配對象,即适配對象本身及其所有子類(如果有的話)。擴充卡還可以同時向所有适配對象添加功能。
  • 使得更難重寫适配對象的方法。這将需要對所有的适配對象進行子類化,并使擴充卡引用适配對象子類而不是适配對象本身。

Java中的現執行個體子

寫在最後

擴充卡對象是我們接觸到的第一個結構型模式,需要注意的是擴充卡模式一般不是在新的程式設計時使用和添加的,而是在解決正在服役的項目内外接口相容性問題的。

說實話,我們應該熟練掌握這種設計模式,因為大多數時候我們是來解決現役項目問題的。

是以接下來我們再來編寫一個擴充卡模式小程式,就以上面經典的電腦讀取記憶體SD卡的資料為例。

首先電腦通過USB接口可以讀取讀卡器中的資料,而讀卡器可以讀取SD記憶體卡中的資料。按此思路畫出程式UML類圖如下:

根據類圖我們開始編寫程式,步驟一定義電腦擴充接口ComputerExtendInterface和MicroSD閃存卡類:

public interface ComputerExtendInterface {

    void usbReadData();
}

public class MicroSD
{
    private static Logger loggger = LoggerFactory.getLogger(MicroSD.class);


    public void readSD(){

        loggger.info("reading data from Micro SD....");
    }
}           

步驟二定義擴充卡類讀卡器:

/**
 * 适配MicroSD 到ComputerExtendInterface 接口
 */
public class ReadCardAdapter implements ComputerExtendInterface{

    private MicroSD microSD;

    public ReadCardAdapter(){
        this.microSD = new MicroSD();
    }


    @Override
    public void usbReadData() {

        microSD.readSD();
    }
}           

步驟三定義适配用戶端電腦類:

public class Computer {

    private ComputerExtendInterface extendInterface;

    public  Computer(ReadCardAdapter readCardAdapter){

        this.extendInterface = readCardAdapter;
    }

    /**
     * 讀取資料
     */
    public void readData(){

        extendInterface.usbReadData();
    }
}           

步驟四完成App的調用編寫:

public class App {

    public static void main(String[] args) {
        Computer computer = new Computer(new ReadCardAdapter());
        computer.readData();
    }
}           

運作App輸出結果如下:

19:39:48.552 [main] INFO com.lyp.adapter.MicroSD - reading data from Micro SD....           

下一篇文章我們将學習結構性模式中的橋接模式(Bridge Pattern)

碼字不易,各位看官如果喜歡的話,請給點個喜歡 ️,關注下我,我将努力持續不斷的為大家更新