歡迎轉載,請註明出處。
1、核心意圖: 將一個類的介面轉換成客戶希望的另外一個介面,從而使得原本由於介面不相容而不能一起工作的類可以一起工作。該模式的目標是通過一個代理(這裡是Adapter),在原來的類(Adaptee)和客戶(Client)之間進行協調,從而達到相容的目的。其核心是解決一致性的問題。
2、身邊執行個體:在我們實際生活中也很容易看到這方面的例子,比如我們要和一個外國人打交道,例如韓國人,如果我們沒有學習過韓語,這個韓國人也沒有學習過我們漢語,在這種情況下,我們之間是很難進行直接交流溝通。為了達到溝通的目的有兩個方法:1)改造這個韓國人,使其能夠用漢語進行溝通;2)請一個翻譯,在我們和這個韓國人之間進行語言的協調。顯然第一種方式——改造這個韓國人的代價要高一些,我們不僅要重新培訓他漢語的學習,還有時間、態度等等因素。而第二個方式——請一個翻譯,就很好實現,而且成本低,還比較靈活,當我們想換個日本人,再換個翻譯就可以了。
3、動機簡述:在該模式的動機中,描述了一個繪圖編輯器的實現,該編輯器可以對基本圖元Shape(直線、多邊形、本文等)進行繪製和排列來產生圖片和圖表,對於這些圖元類的實現,直線/多邊形還比較容易實現,但是本文的實現卻很麻煩,為了減少開發成本和保證品質,通過採用Adapter模式定義適配器類TextShape,來重用圖形工具箱中已經存在的本文編輯器TextView。
4、Java實現分析:在GOF設計模式中,Adapter可以分為類模式和對象模式兩種,類模式通過多重繼承實現,對象模式通過委託實現。在Java中由於沒有多重繼承機制,所以要想實作類別模式的Adapter,就要進行相應的改變:通過繼承Adaptee類實現Target介面方式實現。這種改變存在兩個問題:1)Target必須是一個介面而不能是一個類,否則Adapter無法implements實現;2)Adapter是繼承Adaptee的實現,而不是私人繼承,這就表示Adapter是一個Adaptee的子類。類Adapter模式和對象Adapter模式的Java代碼可參考本文下方代碼部分。
5、類模式/對象模式分析:由於存在兩種Adapter實現方式(即使在Java中),那麼在實際中我們採用哪一種要好呢?通過分析發現這兩種模式有兩個主要特性區別,並且還是互補的:
A、表現在Adapter對Adaptee的特殊性要求:類模式由於Adapter是Adaptee的子類,所以Adapter很方便重新定義Adaptee中的個別方法,以達到自己的特性需要。對象模式由於Adapter不是Adaptee的子類,所以如果Adapter對Adaptee中的個別方法有特殊的需要,就要建立Adaptee的子類,而讓Adapter使用這個子類。
B、表現在Adaptee的類層次擴充上:類模式由於Adapter是Adaptee的子類,所以編譯後就不能再更換所實現的父類Adaptee,因此如果有一個Adaptee的類階層,就要相應的有一個Adapter的類階層,且新擴充Adaptee時很不方便。對象模式由於Adapter不是Adaptee的子類,而是通過使用的方式,所以在系統運行時仍然可以更換Adapter所使用的Adaptee,只要他們具有相同的類型。所以在新擴充Adaptee時很方便。
6、Java程式碼範例—對象模式實現:類Point,表示畫面座標中的點
package qinysong.pattern.adapter;public class Point { private int coordinateX; private int coordinateY; public Point(int coordinateX, int coordinateY){ this.coordinateX = coordinateX; this.coordinateY = coordinateY; } public String toString(){ return "Point[x=" + coordinateX + ",y=" + coordinateY + "]"; } public int getCoordinateX() { return coordinateX; } public int getCoordinateY() { return coordinateY; }}
類Shape,表示圖元借口,對應Adapter模式中的Target
package qinysong.pattern.adapter;public interface Shape { public Point getBottomLeftPoint(); public Point getTopRightPoint();}
類TextView,工具箱中的文本組件類,已經存在的類,對應Adapter模式中的Adaptee
package qinysong.pattern.adapter;public class TextView { public int getCoordinateX() { System.out.println("TextView.getCoordinateX()..."); return 10; } public int getCoordinateY() { System.out.println("TextView.getCoordinateY()..."); return 20; } public int getHeight() { System.out.println("TextView.getHeight()..."); return 30; } public int getWidth() { System.out.println("TextView.getWidth()..."); return 40; } public boolean isEmpty(){ return false; }}
類TextShape,對象模式實現的Adapterpackage qinysong.pattern.adapter;
public class TextShape implements Shape { private TextView textView; public TextShape(TextView textView){ this.textView = textView; } //通過TextView的執行個體進行協調實現 public Point getBottomLeftPoint() { System.out.println("TextShape.getBottomLeftPoint()..."); int coordinateX = textView.getCoordinateX(); int coordinateY = textView.getCoordinateY(); return new Point(coordinateX, coordinateY); } //通過TextView的執行個體進行協調實現 public Point getTopRightPoint() { System.out.println("TextShape.getTopRightPoint()..."); int coordinateX = textView.getCoordinateX(); int coordinateY = textView.getCoordinateY(); int height = textView.getHeight(); int width = textView.getWidth(); return new Point(coordinateX + width, coordinateY + height); }}
類Client,Adapter模式的客戶
package qinysong.pattern.adapter;public class Client { public static void main(String[] args){ System.out.println("Client.main begin .........."); System.out.println("Client.main 以下是通過執行個體委託方式實現的Adapter"); Shape shape = new TextShape(new TextView()); Point bottomLeft = shape.getBottomLeftPoint(); Point topRight = shape.getTopRightPoint(); System.out.println("Client.main shape's bottomLeft:" + bottomLeft); System.out.println("Client.main shape's topRight:" + topRight); System.out.println(" Client.main 以下是通過類繼承方式實現的Adapter"); Shape shape2 = new TextShape2(); bottomLeft = shape2.getBottomLeftPoint(); topRight = shape2.getTopRightPoint(); System.out.println("Client.main shape2's bottomLeft:" + bottomLeft); System.out.println("Client.main shape2's topRight:" + topRight); System.out.println("Client.main end .........."); }}
7、Java程式碼範例—類模式實現:和以上對象模式實現中的樣本目的相同,類Point、Shape、TextView相同,略。以下是類TextShape2的範例程式碼,實作類別模式的Adapter
package qinysong.pattern.adapter;public class TextShape2 extends TextView implements Shape { //通過所繼承的TextView,進行協調實現 public Point getBottomLeftPoint() { System.out.println("TextShape2.getBottomLeftPoint()..."); int coordinateX = getCoordinateX(); int coordinateY = getCoordinateY(); return new Point(coordinateX, coordinateY); } //通過所繼承的TextView,進行協調實現 public Point getTopRightPoint() { System.out.println("TextShape2.getTopRightPoint()..."); int coordinateX = getCoordinateX(); int coordinateY = getCoordinateY(); int height = getHeight(); int width = getWidth(); return new Point(coordinateX + width, coordinateY + height); } //注意: 這一點體現了類模式的優勢,可以很方便地重定義父類TextView中的方法 public int getCoordinateX() { System.out.println("TextShape2.getCoordinateX()..."); return 100; }}