適配器主要用於接口的轉換或者將接口不兼容的類對象組合在一起形成對外統一接口,是一種結構性模式,其本質是是一個中間件,適用於類及其對象。
本文希望通過簡單的介紹和分析,能讓讀者對適配器模式有一個簡單直觀的認識和感知。
1.目的
對現有的類的接口進行轉換以符合新的需求。
2.動機
通過轉換或者組合,間接復用已有功能模塊完成需求。
3.優缺點
優點:
- 提高了類的復用;
- 組合若干關聯對象形成對外提供統一服務的接口;
- 擴展性、靈活性好。
缺點:
- 過多使用適配模式容易造成代碼功能和邏輯意義的混淆。
- 部分語言對繼承的限制,可能至多只能適配一個適配者類,而且目標類必須是抽象類。
4.分類
- 類適配器
- 對象適配器
- 接口適配器
本文主要介紹前兩者。
5.主要用途及場景
該模式並不是在設計開發階段考慮的,主要用在想要修改一個已經存在的接口,或者組合若干關聯對象的時候。
- 想用一個已經存在的類,但其接口不符合需求;
- 想創建一個可以復用的類,該類可以與其他不相關的類協同工作;
- 想使用一些已經存在的子類,但是不能對每一個都進行子類化以匹配它們的接口(僅適用於對象Adapter)。對象適配器可以適配他的父類接口。
6.原理
下面是GoF介紹的典型的類適配器模式和對象適配器模式的UML類圖
類適配器
原理:通過類繼承實現適配,繼承Target的接口,繼承Adaptee的實現
對象適配器
原理:通過類對象組合實現適配
Target:
定義Client真正需要使用的接口。
Adaptee:
其中定義了一個已經存在的接口,也是我們需要進行適配的接口。
Adapter:
對Adaptee和Target的接口進行適配,保證對target中接口的調用可以間接轉換為對Adaptee中接口進行調用。
7.實現
接下來先將上面的UML類圖轉換為兩個具體的例子,然后在對每一種類型在使用一個具體例子介紹.
下面我們使用幾個例子來實際體驗一下代理模式的應用。
7.1 類適配器
定義目標接口類:Target
public interface Target { void request(); }
被適配的類:Adaptee
public class Adaptee { public void adapteeRequest() { System.out.println("adapteeRequest method of Adaptee! "); } }
適配類Adapter,繼承Target的接口request,同時繼承Adaptee的實現adapteeRequest
public class Adapter extends Adaptee implements Target { @Override public void request() { // TODO Auto-generated method stub super.adapteeRequest(); } }
演示:
public class Demo { public static void main(String [] args) { Target target = new Adapter(); target.request(); // result: adapteeRequest method of Adaptee! } }
7.2 對象適配器
從上面兩張UML圖中可以清楚的看出兩者的區別,對象中Adapter不在繼承Adaptee,而是將Adaptee作為一個數據成員組合到類定義中,從而實現對其接口的訪問。
public class Adapter implements Target { private Adaptee adaptee = new Adaptee(); @Override public void request() { // TODO Auto-generated method stub adaptee.adapteeRequest(); } }
7.3 類適配器實例——排序
考慮到某系統中有對數據排序的需求,下面使用適配器看一下如何復用現有的排序接口(下面的例子僅僅為了演示,接口不具實際意義);
現有排序類:EffectiveVectorSort
public class EffectVectorSort { public void vectorSort() { System.out.println("vectorSort method of EffectVectorSort! "); } }
系統排序所需的接口類定義:DataSort
public interface DataSort { void sort(); }
定義適配器:SortAdapter
public class SortAdapter extends EffectVectorSort implements DataSort { @Override public void sort() { // TODO Auto-generated method stub super.vectorSort(); } }
演示:
public class Demo { public static void main(String [] args) { DataSort dataSort = new SortAdapter(); dataSort.sort(); // vectorSort method of EffectVectorSort! } }
7.4對象適配器實例——排序
如果系統中不僅有對向量Vector的排序,也有對元組Tuple和鏈表LinkList等高級數據結構的排序,那么顯然通過無法通過類適配將每一個排序類的子類都繼承。這里便可以用到對象適配。
需要修改7.3中的SortAdapter,同時需要定義高級數據結構的排序類。
高級數據結構排序類接口:AdvanceDataSort
public interface AdvanceDataSort { void sort(); }
鏈表排序類:LinkListSort
public class LinkListSort implements AdvanceDataSort { @Override public void sort() { // TODO Auto-generated method stub System.out.println("sort method of LinkListSort!"); } }
元組排序類:TupleSort
public class TupleSort implements AdvanceDataSort { @Override public void sort() { // TODO Auto-generated method stub System.out.println("sort method of TupleSort"); } }
重定義適配器:SortAdapter
public class SortAdapter implements DataSort { private EffectVectorSort vectorSort = new EffectVectorSort(); private AdvanceDataSort listSort = new LinkListSort(); private AdvanceDataSort tupleSort = new TupleSort(); @Override public void sort(String dataType) { // TODO Auto-generated method stub if(dataType == "vector") { vectorSort.vectorSort(); } else if(dataType == "linklist") { listSort.sort(); } else if(dataType == "tuple") { tupleSort.sort(); } else { System.out.println("Invalid Data Type:" + dataType); } } }
演示:
public class Demo { public static void main(String [] args) { DataSort dataSort = new SortAdapter(); dataSort.sort("vector"); // vectorSort method of EffectVectorSort! dataSort.sort("linklist"); // sort method of LinkListSort! dataSort.sort("tuple"); // sort method of TupleSort dataSort.sort("dict"); // Invalid Data Type:dict } }
限於篇幅,先介紹到這里。上面的例子都是比較直觀,簡單的。好好體會,將其應用到實際編程中才是我們的目的。
參考:
GoF《Design Patterns: Elements of Reusable Object-Oriented Software》
https://www.runoob.com/design-pattern/adapter-pattern.html