網頁

2019/11/24

Java 設計模式 轉接器模式 Adapter Pattern

Adapter Pattern(轉接器模式)屬於設計模式中Structural Patterns(結構模式)。當客戶端想利用一個既有類別的功能,但該類別的介面不同於客戶端所使用的型態,可利用Adapter Pattern來解決。

Adapter Pattern用來把一個介面(Interface)轉換成另一個介面,作用如同硬體的轉接器一樣,例如USB type C轉HDMI接頭,HDMI轉D-Sub接頭。


Adapter Pattern包含以下角色。

  • Client:客戶端,使用Target實例的對象。
  • Target:被Client使用的物件介面,此介面的物件想利用既有的Adaptee實作物件的某個功能。
  • Adaptee:被轉接的介面,其既有實作的功能需要被Target使用。
  • Adapter:轉接器類別,用來轉接Target與Adaptee。




以下是Adapter Pattern範例。

Client為Main,原本利用Target Exporter介面的實作ExportUtil輸出字串內容到某處,例如另一個系統。

不過現在有新需求,同時要將字串內容匯出為檔案到目前的系統目錄,而剛好目前有一個既有的Writer介面的實作FileWriter.write(byte[] byte)可以將byte[]資料寫出為檔案,此即為要被Target利用的Adaptee對象。

由於Writer.write(byte[] bytes)Exporter.export(String content)接收的參數型態不同,為了讓Exporter可以直接利用FileWriter來寫出檔案,所以建立一個Adapter類別WriterAdapter作為連結Exporter.exportWriter.write的轉接器。

經由WriterAdapter的轉接,Exporter便可以直接利用FileWriter.write()將字串內容寫出為檔案了。

/** Client */
public class Main {

    public static void main(String[] args) {
        
        String content = "...";
        
        Exporter exportUtil = new ExportUtil();
        exportUtil.export(content); // export to somewhere
        
        System.out.println("===========================");
        
        Exporter fileWriterExporter = new WriterAdapter(new FileWriter("file.txt"));
        fileWriterExporter.export(content); // export to file.txt

    }

}

/** Target */
interface Exporter {
    void export(String content);
}

/** Target concrete class */
class ExportUtil implements Exporter {

    @Override
    public void export(String content) {
        System.out.println("export content to somewhere");
    }
    
}

/** Adaptee */
interface Writer {
    
    void write(byte[] bytes);
    
}

/** Adaptee concrete class*/
class FileWriter implements Writer {
    
    private String fileName;
    
    public FileWriter(String fileName) {
        this.fileName = fileName;
    }

    @Override
    public void write(byte[] bytes) {
        System.out.println("write to " + fileName);
    }
    
}

/** Adapter */
class WriterAdapter implements Exporter {
    
    private Writer writer;
    
    public WriterAdapter(Writer writer) {
        this.writer = writer;
    }

    @Override
    public void export(String content) {
        writer.write(content.getBytes());
    }
    
}

執行結果如下。

export content to somewhere
===========================
write to file.txt

Adapter Pattern的好處是不用動到既有的程式碼,只要透過新增一個轉接器類別即可讓原本因參數或型態不同無法互相利用的兩個介面變得可以互通。。

使用Adapter Pattern的時機為,

  • 需要使用既有的類別功能,但該類別的介面與目前使用的類別介面不符的時候。
  • 需要使用多個類別的現有功能,而一一去繼承每個類別的介面並不實際的時候。
  • 需要使用第三方函式庫的類別功能,而沒有原始碼且無法改動第三方函式庫的時候。

現實中Adapter Pattern範例包括:

  • Spring MVC的RequestMappingHandlerAdapter
  • Spring MVC的WebMvcConfigurerAdapter
  • Spring Security的WebSecurityConfigurerAdapter
  • Spring JDBC的NamedParameterJdbcTemplate

Adapter Pattern與Decorator Pattern,Proxy Pattern,Bridge Pattern,Facade Pattern等類似,但要解決的問題不同。


參考:

沒有留言:

張貼留言