php模式設計之 適配器模式

何時會用到適配器模式?

其實最簡單的例子是當咱們引用一個第三方類庫。這個類庫隨着版本的改變,它提供的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>

<說明>

  1. 目標(Target)角色:定義客戶端使用的與特定領域相關的接口,這也就是咱們所期待獲得的

這裏的RedTarget及GreenTarget分別爲紅棗公司及綠棗公司要求實現的相關接口。咱們能夠看到RedTarget必須實現doMouthOpen跟doMouthClose兩個方法,GreenTarget必須實現opertateMouth一個方法就好了

  1. 源(Adaptee)角色:須要進行適配的接口

    這裏的源角色是黑棗公司的Toy實例

  2. 適配器(Adapter)角色:對Adaptee的接口與Target接口進行適配;適配器是本模式的核心,適配器把源接口轉換成目標接口,此角色爲具體類

RedAdapter及GreenAdapter分別實現了RedTarget及GreenTarget接口,建立時接收一個Toy實例。

咱們如今面臨這麼一個問題,新的接口方法我要實現,舊的接口(Toy抽象類)也不能動,那麼總得有個解決方法吧。那就是引入一個新的類--咱們本文的主角--適配器。 適配器要完成的功能很明確,引用現有接口的方法實現新的接口的方法。更像它名字描述的那樣,你的接口不改的話,我就利用現有接口和你對接一下吧。

<代碼>

  1. 源(Adaptee)角色: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";  
    }  
}
  1. 目標(Target)角色接口
//目標角色:紅棗遙控公司  
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類及其子類在不改變自身的狀況下,經過適配器實現了不一樣的接口。

最後總結

  將一個類的接口轉換成客戶但願的另一個接口,使用本來不兼容的而不能在一塊兒工做的那些類能夠在一塊兒工做.

  適配器模式核心思想:把對某些類似的類的操做轉化爲一個統一的「接口」(這裏是比喻的說話)--適配器,或者比喻爲一個「界面」,統一或屏蔽了那些類的細節。適配器模式還構造了一種「機制」,使「適配」的類能夠很容易的增減,而不用修改與適配器交互的代碼,符合「減小代碼間耦合」的設計原則。

相關文章
相關標籤/搜索