在這個有沒有對象都要高呼「面向對象」的年代,掌握面向對象會給咱們帶來意想不到的方便。學編程的小夥伴從開始能寫幾行代碼實現簡單功能到後來懂得將一些重複的操做組合起來造成一個「函數」,再到後來將「函數」和屬性組合起來造成一個「類」。一步步走來,咱們在考慮着機器運行代碼效率的提升的同時也在考慮減輕程序員的工做量。 那麼咱們今天講到的適配器模型更着重考慮的是什麼呢?是程序員工做量。php
何時會用到適配器模式?html
其實最簡單的例子是當咱們引用一個第三方類庫。這個類庫隨着版本的改變,它提供的API也可能會改變。若是很不幸的是,你的應用裏引用的某個API已經發生改變的時候,除了在心中默默地罵「wocao」以外,你還得去硬着頭皮去改大量的代碼。 程序員
難道真的必定要如此嗎?按照套路來講,我會回答「不是的」。咱們有適配器模式啊~~ 編程
當接口發生改變時,適配器模式就派上了用場。函數
舉個栗子post
若是經過上面的簡單描述,你都能懂,那在下只能佩服你的領悟能力超羣了。通常人必定仍是不知所云。爲了方便理解,我引用一位博友的例子。原文地址。優化
一開始的和諧
this
黑棗玩具公司專門生產玩具,生產的玩具不限於狗、貓、獅子,魚等動物。每一個玩具均可以進行「張嘴」與「閉嘴」操做,分別調用了openMouth與closeMouth方法。url
在這個時候,咱們很容易想到能夠第必定義一個抽象類Toy,甚至是接口Toy,這些問題不大,其餘的類去繼承父類,實現父類的方法。一片和諧,信心向榮。spa
平衡的破壞
爲了擴大業務,如今黑棗玩具公司與紅棗遙控公司合做,紅棗遙控公司可使用遙控設備對動物進行嘴巴控制。不過紅棗遙控公司的遙控設備是調用的動物的doMouthOpen及doMouthClose方法。黑棗玩具公司的程序員如今必需要作的是對Toy系列類進行升級改造,使Toy能調用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(); } }
更加煩躁
程序員剛剛碼完代碼,喝了口水,忽然間另外一個消息傳來。
黑棗玩具公司也要與綠棗遙控公司合做,由於綠棗遙控公司遙控設備更便宜穩定。不過綠棗遙控公司的遙控設備是調用的動物的operMouth($type)方法來實現嘴巴控制。若是$type爲0則「閉嘴」,反之張嘴。
這下好了,程序員又得對Toy及其子類進行升級,使Toy能調用operMouth()方法。擱誰都不淡定了。
abstract class Toy { public abstract function openMouth(); public abstract function closeMouth(); public abstract function doMouthOpen(); public abstract function doMouthClose(); //爲綠棗遙控公司控制接口增長doMouthClose方法 public abstract function operateMouth($type = 0); } 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(); } public function operateMouth($type = 0) { if ($type == 0) { $this->closeMouth(); } else { $this->operateMouth(); } } } 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(); } public function operateMouth($type = 0) { if ($type == 0) { $this->closeMouth(); } else { $this->operateMouth(); } } }
在這個時候,程序員必需要動腦子想辦法了,就算本身勤快,萬一哪天紫棗青棗黃棗山棗這些遙控公司全來的時候,忽略本身不斷增多的工做量不說,這個Toy類但是愈來愈大,總有一天程序員不崩潰,系統也會崩潰。
問題在出在哪裏呢?
像上面那樣編寫代碼,代碼實現違反了「開-閉」原則,一個軟件實體應當對擴展開放,對修改關閉。即在設計一個模塊的時候,應當使這個模塊能夠在不被修改的前提下被擴展。也就是說每一個屍體都是一個小王國,你讓我參與你的事情這個能夠,但你不能修改個人內部,除非個人內部代碼確實能夠優化。
在這種想法下,咱們懂得了如何去用繼承,如何利用多態,甚至如何實現「高內聚,低耦合」。
回到這個問題,咱們如今面臨這麼一個問題,新的接口方法我要實現,舊的接口(Toy抽象類)也不能動,那麼總得有個解決方法吧。那就是引入一個新的類--咱們本文的主角--適配器。 適配器要完成的功能很明確,引用現有接口的方法實現新的接口的方法。更像它名字描述的那樣,你的接口不改的話,我就利用現有接口和你對接一下吧。
到此,解決方法已經呼之欲出了,下面貼上代碼。
<?php 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); } //類適配器角色:紅棗遙控公司 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(); } } } 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類及其子類在不改變自身的狀況下,經過適配器實現了不一樣的接口。
最後總結
將一個類的接口轉換成客戶但願的另一個接口,使用本來不兼容的而不能在一塊兒工做的那些類能夠在一塊兒工做.
適配器模式核心思想:把對某些類似的類的操做轉化爲一個統一的「接口」(這裏是比喻的說話)--適配器,或者比喻爲一個「界面」,統一或屏蔽了那些類的細節。適配器模式還構造了一種「機制」,使「適配」的類能夠很容易的增減,而不用修改與適配器交互的代碼,符合「減小代碼間耦合」的設計原則。
以上
系列文章: