其實最簡單的例子是當咱們引用一個第三方類庫。這個類庫隨着版本的改變,它提供的API也可能會改變。若是很不幸的是,你的應用裏引用的某個API已經發生改變的時候,除了在心中默默地罵「wocao」以外,你還得去硬着頭皮去改大量的代碼。程序員
難道真的必定要如此嗎?按照套路來講,我會回答「不是的」。咱們有適配器模式啊~~測試
當接口發生改變時,適配器模式就派上了用場。this
黑棗玩具公司專門生產玩具,生產的玩具不限於狗、貓、獅子,魚等動物。每一個玩具均可以進行「張嘴」與「閉嘴」操做,分別調用了openMouth與closeMouth方法。設計
abstract class Toy { public abstract function openMouth(); public abstract function closeMouth(); } class Dog extends Toy { public function openMouth() { echo "Dog open Mouth\n"; } public function closeMouth() { echo "Dog open Mouth\n"; } } class Cat extends Toy { public function openMouth() { echo "Cat open Mouth\n"; } public function closeMouth() { echo "Cat open Mouth\n"; } }
黑棗玩具公司與紅棗遙控公司合做,紅棗遙控公司可使用遙控設備對動物進行嘴巴控制。不過紅棗遙控公司的遙控設備是調用的動物的doMouthOpen及doMouthClose方法。黑棗玩具公司的程序員如今必需要作的是對Toy系列類進行升級改造,使Toy能調用doMouthOpen及doMouthClose方法.code
<實現分析>blog
這不是至關簡單麼,爲Toy再增長doMouthOpen及doMouthClose方法,修改Dog類、Cat類等並實現doMouthOpen及doMouthClose方法就能夠了。雖然有點小繁瑣,工程量還不大。繼承
<程序猿的代碼實現紅棗遙控公司需求>接口
abstract class Toy { public abstract function openMouth(); public abstract function closeMouth(); //爲紅棗遙控公司控制接口增長doMouthOpen方法 public abstract function doMouthOpen(); //爲紅棗遙控公司控制接口增長doMouthClose方法 public abstract function doMouthClose(); } class Dog extends Toy { public function openMouth() { echo "Dog open Mouth\n"; } public function closeMouth() { echo "Dog open Mouth\n"; } //增長的方法 public function doMouthOpen() { $this->doMouthOpen(); } //增長的方法 public function doMouthClose() { $this->closeMouth(); } } class Cat extends Toy { public function openMouth() { echo "Cat open Mouth\n"; } public function closeMouth() { echo "Cat open Mouth\n"; } //增長的方法 public function doMouthOpen() { $this->doMouthOpen(); } //增長的方法 public function doMouthClose() { $this->closeMouth(); } }
後面若是紫棗青棗黃棗山棗這些遙控公司全來的時候,忽略本身不斷增多的工做量不說,這個Toy類但是愈來愈大,增長的方法就會不斷的變多。開發
【分析OOA】get
咱們能夠開發,Toy系列類是越來也龐大。紫棗青棗黃棗山棗這些遙控公司全來的時候,總有一天系統會崩潰。
問題出在哪裏。代碼實現違反了「開-閉」
原則,一個軟件實體應當對擴展開放,對修改關閉。即在設計一個模塊的時候,應當使這個模塊能夠在不被修改的前提下被擴展。
如何去用繼承,如何利用多態,甚至如何實現「高內聚,低耦合」。
【設計OOD】
<UML>
<說明>
這裏的RedTarget及GreenTarget分別爲紅棗公司及綠棗公司要求實現的相關接口。咱們能夠看到RedTarget必須實現doMouthOpen跟doMouthClose兩個方法,GreenTarget必須實現opertateMouth一個方法就好了
源(Adaptee)角色:須要進行適配的接口
這裏的源角色是黑棗公司的Toy實例
適配器(Adapter)角色:對Adaptee的接口與Target接口進行適配;適配器是本模式的核心,適配器把源接口轉換成目標接口,此角色爲具體類
RedAdapter及GreenAdapter分別實現了RedTarget及GreenTarget接口,建立時接收一個Toy實例。
咱們如今面臨這麼一個問題,新的接口方法我要實現,舊的接口(Toy抽象類)也不能動,那麼總得有個解決方法吧。那就是引入一個新的類--咱們本文的主角--適配器。 適配器要完成的功能很明確,引用現有接口的方法實現新的接口的方法。更像它名字描述的那樣,你的接口不改的話,我就利用現有接口和你對接一下吧。
<代碼>
abstract class Toy { public abstract function openMouth(); public abstract function closeMouth(); } class Dog extends Toy { public function openMouth() { echo "Dog open Mouth\n"; } public function closeMouth() { echo "Dog close Mouth\n"; } } class Cat extends Toy { public function openMouth() { echo "Cat open Mouth\n"; } public function closeMouth() { echo "Cat close Mouth\n"; } }
//目標角色:紅棗遙控公司 interface RedTarget { public function doMouthOpen(); public function doMouthClose(); } //目標角色:綠棗遙控公司及 interface GreenTarget { public function operateMouth($type = 0); }
3.適配器角色代碼實現
//類適配器角色:紅棗遙控公司 class RedAdapter implements RedTarget { private $adaptee; function __construct(Toy $adaptee) { $this->adaptee = $adaptee; } //委派調用Adaptee的sampleMethod1方法 public function doMouthOpen() { $this->adaptee->openMouth(); } public function doMouthClose() { $this->adaptee->closeMouth(); } } //類適配器角色:綠棗遙控公司 class GreenAdapter implements GreenTarget { private $adaptee; function __construct(Toy $adaptee) { $this->adaptee = $adaptee; } //委派調用Adaptee:GreenTarget的operateMouth方法 public function operateMouth($type = 0) { if ($type) { $this->adaptee->openMouth(); } else { $this->adaptee->closeMouth(); } } }
測試用例Test Case】
class testDriver { public function run() { //實例化一隻狗玩具 $adaptee_dog = new Dog(); echo "給狗套上紅棗適配器\n"; $adapter_red = new RedAdapter($adaptee_dog); //張嘴 $adapter_red->doMouthOpen(); //閉嘴 $adapter_red->doMouthClose(); echo "給狗套上綠棗適配器\n"; $adapter_green = new GreenAdapter($adaptee_dog); //張嘴 $adapter_green->operateMouth(1); //閉嘴 $adapter_green->operateMouth(0); } } $test = new testDriver(); $test->run();
最後的結果就是,Toy類及其子類在不改變自身的狀況下,經過適配器實現了不一樣的接口。
將一個類的接口轉換成客戶但願的另一個接口,使用本來不兼容的而不能在一塊兒工做的那些類能夠在一塊兒工做.
適配器模式核心思想:把對某些類似的類的操做轉化爲一個統一的「接口」(這裏是比喻的說話)--適配器,或者比喻爲一個「界面」,統一或屏蔽了那些類的細節。適配器模式還構造了一種「機制」,使「適配」的類能夠很容易的增減,而不用修改與適配器交互的代碼,符合「減小代碼間耦合」的設計原則。