PHP設計模式-適配器模式

什麼時候會用到適配器模式?

  其實最簡單的例子是當我們引用一個第三方類庫。這個類庫隨着版本的改變,它提供的API也可能會改變。如果很不幸的是,你的應用裏引用的某個API已經發生改變的時候,除了在心中默默地罵“wocao”之外,你還得去硬着頭皮去改大量的代碼。 

  難道真的一定要如此嗎?按照套路來說,我會回答“不是的”。我們有適配器模式啊~~  

  當接口發生改變時,適配器模式就派上了用場。

舉個栗子

  一開始的和諧

  黑棗玩具公司專門生產玩具,生產的玩具不限於狗、貓、獅子,魚等動物。每個玩具都可以進行“張嘴”與“閉嘴”操作,分別調用了openMouth與closeMouth方法。

  在這個時候,我們很容易想到可以第一定義一個抽象類Toy,甚至是接口Toy,這些問題不大,其他的類去繼承父類,實現父類的方法。一片和諧,信心向榮。

 

  平衡的破壞

     爲了擴大業務,現在黑棗玩具公司與紅棗遙控公司合作,紅棗遙控公司可以使用遙控設備對動物進行嘴巴控制。不過紅棗遙控公司的遙控設備是調用的動物的doMouthOpen及doMouthClose方法。黑棗玩具公司的程序員現在必須要做的是對Toy系列類進行升級改造,使Toy能調用doMouthOpendoMouthClose方法。

  考慮實現的方法時,我們很直接地想到,你需要的話我再在我的父類子類裏給你添加這麼兩個方法就好啦。當你一次又一次在父類子類裏面重複添加着這兩個方法的時候,總會想着如此重複的工作,難道不能解決麼?當有數百個子類的時候,程序員會改瘋的。程序員往往比的是誰在不影響效率的時候更會“偷懶”。這樣做下去程序員會覺得自己很傻。

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爲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類及其子類在不改變自身的情況下,通過適配器實現了不同的接口。

  最後總結

  將一個類的接口轉換成客戶希望的另外一個接口,使用原本不兼容的而不能在一起工作的那些類可以在一起工作.

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

   

發佈了17 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章