首頁  >  文章  >  後端開發  >  關於php設計模式-適配器的方法詳解

關於php設計模式-適配器的方法詳解

零到壹度
零到壹度原創
2018-03-17 15:58:111622瀏覽

將一個類別的接口轉換成客戶希望的另外一個接口,Adapter模式使得原來由於接口不相容而不能一起工作的那此類可以一起工作。本文主要和大家分享適配器的詳解,希望能幫助大家。

主要角色

目標角色:定義客戶端使用的與特定領域相關的接口,這就是我們所期待的

#來源角色:需要進行適配的介面

適配器角色:對Adaptee的介面與target介面進行適配器是本模式的核心,適配器將來源介面轉成目標接口,此角色為具體的類別

適用性

1、你想使用一個已經存在的類,而它的介面不符合你的需求

2、你想創建一個可以復用的類,該類可以與其他不相關的類或不可預見的類協同工作

3、你想要一個已經存在的子類,但是不可能對每一個都進行子類化以匹配它們的接口。物件適配器可以適應它的父類別介面(僅限於物件適配器)

//目标角色  
interface Target {  
    public function simpleMethod1();  
    public function simpleMethod2();  
}  
  
//源角色  
class Adaptee {  
      
    public function simpleMethod1(){  
        echo &#39;Adapter simpleMethod1&#39;."<br>";  
    }  
}  
  
//类适配器角色  
class Adapter implements Target {  
    private $adaptee;  
      
      
    function __construct(Adaptee $adaptee) {  
        $this->adaptee = $adaptee;   
    }  
      
    //委派调用Adaptee的sampleMethod1方法  
    public function simpleMethod1(){  
        echo $this->adaptee->simpleMethod1();  
    }  
      
    public function simpleMethod2(){  
        echo &#39;Adapter simpleMethod2&#39;."<br>";     
    }   
      
}  
  
//客户端  
class Client {  
      
    public static function main() {  
        $adaptee = new Adaptee();  
        $adapter = new Adapter($adaptee);  
        $adapter->simpleMethod1();  
        $adapter->simpleMethod2();   
    }  
}  
  
Client::main();

也許上述這麼講,你們還不知道什麼是適配器。那接下來,我再詳細的講解一下

什麼時候使用適配器模式呢?

其實最簡單的一個例子就是使用第三方類別庫。這些類別庫都會隨著版本的升級,對應的api也會改變。當介面改變的時候,適配器就派上用場了

我舉一個實際的例子吧

一開始的和諧

#黑棗玩具公司專門生產玩具,生產的玩具不限於狗、貓、獅子,魚等動物。每個玩具都可以進行「張嘴」與「閉嘴」操作,分別呼叫了openMouth與closeMouth方法。 在這個時候,我們很容易想到可以第一定義一個抽象類別Toy,甚至是介面Toy,這些問題不大,其他的類別去繼承父類,實作父類別的方法。一片和諧,信心向榮。

平滑的破壞

為了擴大業務,現在黑棗玩具公司與紅棗遙控公司合作,紅棗遙控公司可以使用遙控設備對動物進行嘴巴控制。不過紅棗遙控公司的遙控設備是呼叫的動物的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类及其子类在不改变自身的情况下,通过适配器实现了不同的接口。

最后的总结

将一个类的接口转换成客户希望的另外一个接口,使用原本不兼容的而不能在一起工作的那些类可以在一起工作.

适配器模式核心思想:把对某些相似的类的操作转化为一个统一的“接口”(这里是比喻的说话)--适配器,或者比喻为一个“界面”,统一或屏蔽了那些类的细节。适配器模式还构造了一种“机制”,使“适配”的类可以很容易的增减,而不用修改与适配器交互的代码,符合“减少代码间耦合”的设计原则。

以上是關於php設計模式-適配器的方法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn