設計模式之ADAPTER

設計模式之ADAPTER有兩種實現方式組合(composition)和繼承(inheritance).

基本介紹

  • 中文名:設計模式之ADAPTER
  • 實現方式:組合和繼承
  • 組合:composition
  • 繼承:inheritance
日常生活中的適配器,軟體工程中的套用,如何使用,定義,結構,為何使用,幾個要點,進一步使用,現實中的套用,在架構層次上的套用,

日常生活中的適配器

適配器的例子在日常生活中隨處可見。 例如:中國的電源電壓為 220V ,而日本的電源電壓 110V ,在國內使用日本原裝電器時,就必須有一個電源適配器將 220V 的電壓適配至 110V 。
新的電腦滑鼠一般都是 USB 接口,而舊的電腦機箱上根本就沒有 USB 接口,而只有一個 PS2 接口,這時就必須有一個 PS2 轉 USB 的適配器,將 PS2 接口適配為 USB 接口。
一般家庭中電源插座有的是兩個孔(兩項式)的,也有三個孔(三項式)的。很多時候我們可能更多地使用三個引腳的插頭,但是那種兩孔的插座就不能滿足我們的需求,此時我們一般會買一個拖線板,該拖線板的插頭是是兩腳插頭,這樣就可以插入原先的兩孔插座,同時拖線板上帶有很多兩孔、三孔的插座!這樣不僅可以擴容,更主要的是將兩孔的插座轉變為三孔的插座。
圖1為一個將220v 電源轉換為5v 電源的適配器,圖2為將PS2 接頭轉換為 USB 接頭的適配器,,圖3二孔插座適配為三孔插座的插座適配器。

設計模式之ADAPTER設計模式之ADAPTER
圖 1 電源適配器 圖 2 滑鼠適配器

設計模式之ADAPTER設計模式之ADAPTER
圖 3 插座適配器

軟體工程中的套用

如果你有一個存在的系統需要插入一個新的類庫,但是新的類庫並不能匹配你寫的系統,如下圖:

設計模式之ADAPTER設計模式之ADAPTER
現在你不想更改存在的舊系統,新的類庫也不能修改,這時候我們就需要寫一個適配器了,用這個適配器來適配新類庫的接口。如下圖:

設計模式之ADAPTER設計模式之ADAPTER
用了適配器之後的整個系統,如下圖:

設計模式之ADAPTER設計模式之ADAPTER

如何使用

實現Adapter方式,有兩種方式:組合(composition)和繼承(inheritance).
假設我們要打樁,有兩種類:方形樁,圓形樁.public class SquarePeg{ public void insertSquare(String str){ System.out.println("SquarePeg insertSquare():" +str); }
}
public class RoundPeg{ public void insertRound(String msg){ System.out.println("RoundPeg insertRound():" +msg); }}
現在有一個套用 ,需要圓樁能當方樁來打.那么我們需要將這兩個沒有關係的類綜合套用.假設RoundPeg我們沒有原始碼,或原始碼我們不想修改,那么我們使用Adapter來實現這個套用:
public class PegAdapter extends SquarePeg {
private RoundPeg roundPeg;
public PegAdapter(RoundPeg peg) { this.roundPeg = peg;}
public void insertSquare(String str) {roundPeg.insertRound(str); }}
在上面代碼中 ,RoundPeg屬於Adaptee,是被適配者.PegAdapter是Adapter,將Adaptee(被適配者RoundPeg)和target(目標SquarePeg)進行適配.實際上這是將組合方法(composition)和繼承(inheritance)方法綜合運用.
PegAdapter首先繼承SquarePeg,然後使用new的組合生成對象方式,生成RoundPeg的對象roundPeg,再重載父類insertSquare()方法。從這裡,你也了解使用new生成對象和使用extends繼承生成對象的不同,前者無需對原來的類修改,甚至無需要知道其內部結構和原始碼.
如果你有些 Java使用的經驗,已經發現,這種模式經常使用。

定義

轉換一個類的接口為客戶端所需要的接口,將兩個不兼容的類糾合在一起使用,這個轉換的類就是適配器類。它屬於結構型模式,需要有Adaptee(被適配者)和Adaptor(適配器)兩個身份.它的宗旨就是,保留現有類所提供的服務,向客戶提供接口,以滿足客戶的期望。

結構

Adapter模式有兩種結構,分別是類的適配與對象的適配。
1、類的適配

設計模式之ADAPTER設計模式之ADAPTER
角色分析:
Target目標角色:這是一個接口,定義了客戶所期望的操作 Adaptee源角色:這是我們原有的產品,也是需要被適配的產品。
Adapter適配器角色:在Target目標角色與Adaptee源角色之間提供一種過渡,即把Adaptee源角色所提供的接口轉換為Target目標角色所提供的接口。 從結構圖中可以很容易的知道,適配器角色Adapter必須要繼承Targe目標角色(一個接口)與源角色Adaptee。
源碼:
public class Adaptee{
public void specialRequest(){
System.out.println("Called SpecificRequest() in Adaptee ");
}
}
public interface Target{
public void request();
}
public class Adapter extends Adaptee implements Target{
public void request(){
this.specialRequest();
}
}
2、對象的適配
設計模式之ADAPTER設計模式之ADAPTER
兩種結構的角色其實都是一樣的,客戶的調用流程也是相同的。不同之處於兩者在包裝Adaptee源角色時,前者(類適配)包裝的是Adaptee類(因為它同時從Target與Adaptee繼承而來,可想而知,類適配的Adatper必須是一個具體類,而Target只能是一個接口),後者(對象適配)則直接包裝了一個源Adaptee的實例。這一點如果放在代碼中,則更容易體現出來。此處的差別導致了在具體實現時各個角色的不同實現方式(以類還是以接口)。
讓我們來看一下前面講的生活中的適配器例子的插座對象適配圖:

設計模式之ADAPTER設計模式之ADAPTER
源碼: Adaptee和Target類同上。
public class Adapter implements Target{
Adaptee adaptee = new Adaptee();
public void request(){
adaptee.specialRequest();
}
}
3,類適配和對象適配的不同
設計模式之ADAPTER設計模式之ADAPTER

為何使用

我們經常碰到要將兩個沒有關係的類組合在一起使用,第一解決方案是:修改各自類的接口,但是如果我們沒有原始碼,或者,我們不願意為了一個套用而修改各自的接口。 怎么辦? 使用 Adapter,在這兩種接口之間創建一個混合接口(混血兒).
1、 系統需要使用現有的類,而此類的接口不符合系統的需要。2、 想要建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起 工作。這些源類不一定有很複雜的接口。3、 (對對象適配器而言)在設計里,需要改變多個已有子類的接口,如果使用類的適配器模式,就要針對每一個子類做一個適配器,而這不太實際.

幾個要點

1、 Adapter模式主要套用於“希望服用一些現存的類,但是接口又與復用環境要求不一致的情況”,在遺留代碼復用、類庫遷移等方面非常有用。
2、 Gof23定義了兩種 Adapter模式的實現結構:對象適配器和類適配器。但類適配器採用“多繼承”的實現方式 帶來了不良的高耦合,所以一般不推薦使用。對象適配器採用“對象組合”的方式,更符合松耦合精神。
3、 Adapter模式本身要求我們儘可能的使用“面向接口的編程”風格,這樣才能在後期很方便的適配。

進一步使用

上面的PegAdapter是繼承了SquarePeg,如果我們需要兩邊繼承,即繼承SquarePeg 又繼承RoundPeg,因為Java中不允許多繼承,但是我們可以實現(implements)兩個接口(interface)
public interface IRoundPeg{ public void insertRound(String msg);}
public interface ISquarePeg{ public void insertSquare(String str);
}
下面是新的 RoundPeg 和SquarePeg, 除了實現接口這一區別,和上面的沒什麼區別。public class SquarePeg implements ISquarePeg{ public void insertSquare(String str){ System.out.println("SquarePeg insertSquare():"+ str); }
}
public class RoundPeg implements IRoundPeg{ public void insertRound(String msg){ System.out.println("RoundPeg insertRound():"+msg); }}
下面是新的 PegAdapter,叫做two-way adapter:
public class PegAdapter implements IRoundPeg,ISquarePeg{private RoundPeg roundPeg;
private SquarePeg squarePeg;
// 構造方法public PegAdapter(RoundPeg peg) { this.roundPeg = peg;}
// 構造方法public PegAdapter(SquarePeg peg) { this.squarePeg = peg;}
public void insertSquare(String str) { roundPeg.insertRound(str);}
public void insertRound(String msg) {squarePeg.insertSquare(msg);}
}
還有一種叫 Pluggable Adapters,可以動態的獲取幾個adapters中一個。使用Reflection技術,可以動態的發現類中的Public方法。

現實中的套用

在JDK1.0和1.1版本里沒有Java聚集(Collectcion)的框架,這一框架是在JDK1.2版本中給出的。與引起相對應,JDK1.0和1.1版本里提供了Enumeration接口,而JDK1.2版本給出了Iterator接口。如果有很多的Java代碼是為老版本Java編譯器寫的,使用的是Enumeration,現在想使用新版本編譯器和新的Java聚集庫包的話,需要將已有代碼的Iterator接口轉換成Enumeration接口。因為Java聚集要求的Iterator接口,只有這樣才能使已有的代碼可以使用新版本的聚集對象。反之,需要將舊代碼的Enumeration接口轉換成Iterator接口。
Enumeration接口類圖:
<> Enumeration hasMoreElements () nextElement ()
<<interface>> Enumeration
hasMoreElements () nextElement ()
<>
Enumeration
hasMoreElements ()
nextElement ()
Iterator接口類圖:
<> Iterator hasnext () next () remove ()
<<interface>> Iterator
hasnext () next () remove ()
<>
Iterator
next ()
remove ()
適配Enumeration成為Iterator:

設計模式之ADAPTER設計模式之ADAPTER
適配Enumeration成為Iterator的原始碼:
public class EnumerationIterator implements Iterator{ Enumeration enum; public EnumerationIterator(Enumeration enum){ this.enum=enum; }public boolean hasNext(){ return enum.hasMoreElements(); } public Object next(){ return enum.nextElement(); } public void remove(){ throw new UnsupportedOperationException(); }}

在架構層次上的套用

1,JDBC驅動軟體與適配器模式
Sun Microsystem在1996年公開了Java語言的資料庫連線工具JDBC。JDBC使得Java語言程式能夠連線資料庫上,並使用SQL(Strucured Query Language)來查詢和修改數據和數據定義。
JDBC給出一個客戶端通用的界面。每個資料庫引擎的JDBC驅動軟體都是一個介於JDBC接口和資料庫引擎接口之間的適配器軟體,如下圖所示。

設計模式之ADAPTER設計模式之ADAPTER
抽象的JDBC接口和各個資料庫引擎的API之間都需要相應的適配器軟體,即為各個資料庫引擎準備的驅動軟體。
2,JDBC/ODBC橋樑
JDBC的想法與微軟的ODBC想法很接近。只要有合適的驅動軟體,JDBC就可以直接連線到資料庫上。如果沒有合適的JDBC驅動軟體,用戶也可以通過ODBC驅動軟體把JDBC通過一個JDBC/ODBC橋樑軟體與ODBC驅動軟體連線起來,從而達到連線資料庫的目的。ODBC/JDBC橋樑的架構圖如下圖所示。

設計模式之ADAPTER設計模式之ADAPTER
JDBC庫不可能和ODBC的庫有相同的接口,因此,使用適配器模式將ODBC的API接口改為JDBC的接口就是唯一可行的方法。因此,JDBC/ODBC橋樑是適配器模式的具體套用。

相關詞條

熱門詞條

聯絡我們