適配器模式提供了將一種對象轉換成另外一種對象的能力,利用它能夠實現兩個不兼容接口的協調工做。外觀模式是封裝對象內的複雜邏輯,對外提供一個簡化的接口。html
生活中最多見的適配器的使用場景就是各類轉換線和轉換插頭,例如投影儀到電腦之間的轉換線,港版iPhone和國內插座之間的轉換插頭等。下面就以iPhone和插座之間的轉換插頭爲例來看看適配器模式的用法。設計模式
港版iPhone使用的英式插頭,如左圖所示,這種插頭無法直接插在國內的標準插座上,要使用相似右圖的轉換器才行,那麼如今須要作的就是找到一個轉換器(適配器),將英式插頭轉換成符合國內標準的插頭,也就是將EnglishPlug轉換成ChinesePlug。(注:下面兩個圖片來源:https://zhidao.baidu.com/question/1365859698524477699.html)ide
先看一下插頭的定義:測試
1 public interface EnglishPlug{ 2 void charge(); // 英式插頭能夠插到插座上充電 3 } 4 5 public interface ChinesePlug{ 6 void charge(); // 中式插頭也能夠插到插座上充電 7 }
接下來是英式iPhone插頭和中式iPhone插頭:this
1 public class EnglishiPhonePlug implements EnglishPlug{ 2 @Override 3 public void charge(){ 4 System.out.println("英式插頭在充電"); 5 } 6 } 7 8 public class ChineseiPhonePlug implements ChinesePlug{ 9 @Override 10 public void charge(){ 11 System.out.println("中式插頭在充電"); 12 } 13 }
因爲兩個插頭都已經作好了,回爐重造確定是不可能了,只能增長一個轉換器PlugConverter,將EnglishPlug假裝成ChinesePlug,好讓英式插頭能在中式插座上充電。要假裝成ChinesePlug,就須要讓PlugConverter實現ChinesePlug接口,在轉換器中組合EnglishPlug來完成轉換工做,代碼以下:spa
1 publich class IPhonePlugConverter implements ChinesePlug{ 2 private EnglishPlug englishPlug; 3 4 public IPhonePlugConverter(EnglishPlug englishPlug){ 5 this.englishPlug = englishPlug; 6 } 7 8 @Override 9 public void charge(){ 10 englishPlug.charge(); 11 } 12 }
如今須要寫一個測試類來看看這個轉換成到底能不能用:設計
1 public static void main(String[] args){ 2 ChinesePlug chinesePlug = new IPhonePlugConverter(new EnglishiPhonePlug()); 3 chinesePlug.charge(); //輸出:英式插頭在充電 4 }
能夠看到,咱們成功的用EnglishPlug「冒充」了ChinesePlug,實現了轉換器的功能。固然,上面介紹的只是講一個接口轉換成另外一個接口,實際上能夠將一個接口轉換爲多個其餘接口。code
外觀模式提供了簡化接口的能力,將內部複雜的實現封裝起來,開放給外部一個簡單的接口,從而下降使用的複雜性。htm
以洗衣機爲例,洗衣機有半自動和全自動兩種,半自動洗衣機須要咱們本身先注水,而後洗滌,放水,最後脫水,這幾部須要咱們手動一步一步完成,雖然能夠作到精細化控制(例如能夠自由選擇注水多少,脫水幾分鐘),可是用起來難免有些麻煩,而全自動洗衣機只須要按下啓動鍵就OK了,簡單了許多。對象
下面是半自動洗衣機的定義:
1 public class SemiautoWashingMachine{ 2 public void addWater(){ 3 System.out.println("手動注水"); 4 } 5 6 public void washing(){ 7 System.out.println("開始洗衣服"); 8 } 9 10 public void drainage(){ 11 System.out.println("手動排水"); 12 } 13 14 public void dehydration(){ 15 System.out.println("手動脫水"); 16 } 17 }
用戶使用半自動洗衣機,須要一步一步分別調用addWater(),washing(), drainage(), dehydration()這些接口。
全自動洗衣機定義以下:
1 public class FullautoWashingMachine{ 2 public void addWater(){ 3 System.out.println("手動注水"); 4 } 5 6 public void washing(){ 7 System.out.println("開始洗衣服"); 8 } 9 10 public void drainage(){ 11 System.out.println("手動排水"); 12 } 13 14 public void dehydration(){ 15 System.out.println("手動脫水"); 16 } 17 18 //對外提供的簡單接口 19 public void simpleWashing(){ 20 this.addWater(); 21 this.washing(); 22 this.drainage(); 23 this.dehydration(); 24 } 25 }
用戶使用全自動洗衣機,就只須要調用simyleWashing()就好了。
從上面能夠看出來, 外觀模式並無增長新的功能,只是將原來的一些操做封裝到一個接口裏面,對外提供了一個簡單的接口,避免讓用戶解除到底層,讓系統更加容易使用。固然,若是你願意,對象原來的一些底層功能(addWater()等方法)你仍然能夠自由使用,像半自動洗衣機那樣,每一步都手動來操做,只不過這樣一來,用戶就與對象的底層細節耦合在一塊兒了。
總的來講,適配器模式提供了講一個接口轉換成其餘接口的能力,而無需修改原來的接口;外觀模式提供簡化接口的能力,讓使用者與接口內部的細節解耦,符合「最小知道原則」。
<<Head First設計模式>>