最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PHP設(shè)計(jì)模式之適配器模式(Adapter)原理與用法詳解

 更新時(shí)間:2019年12月12日 10:53:43   作者:luyaran  
這篇文章主要介紹了PHP設(shè)計(jì)模式之適配器模式(Adapter)原理與用法,結(jié)合實(shí)例形式詳細(xì)分析了適配器模式的概念、原理、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例講述了PHP設(shè)計(jì)模式之適配器模式(Adapter)原理與用法。分享給大家供大家參考,具體如下:

這個(gè)適配器模式,就是為了將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口,并且使用原本不兼容的而不能在一起工作的那些類可以在一起工作。它的核心思想就是把對某些相似的類的操作轉(zhuǎn)化為一個(gè)統(tǒng)一的“接口”(這里是比喻的說話)--適配器,或者比喻為一個(gè)“界面”,統(tǒng)一或屏蔽了那些類的細(xì)節(jié)。適配器模式還構(gòu)造了一種“機(jī)制”,使“適配”的類可以很容易的增減,而不用修改與適配器交互的代碼,符合“減少代碼間耦合”的設(shè)計(jì)原則。

我們來考慮下開發(fā)過程中,我們引用一個(gè)第三方類庫的場景,這個(gè)類庫隨著版本的改變,它提供的API也可能會(huì)改變。如果很不幸的是,你的應(yīng)用里引用的某個(gè)API已經(jīng)發(fā)生改變的時(shí)候,除了在心中默默地罵“wocao”之外,你還得去硬著頭皮去改大量的代碼,這個(gè)時(shí)候,為了減少工作量,我們就可以使用適配器模式。

先來看一個(gè)網(wǎng)上的案例:

  • 假如我們原始的有一個(gè)UserInfo的類,提供用戶信息的類,早起設(shè)計(jì)該類的時(shí)候,只實(shí)現(xiàn)了一個(gè)getUserName獲取用戶名的方法。
  • 我們的MyOldObject類中,將從UserInfo這個(gè)類中獲取用戶信息,并且輸出用戶名
  • 隨著時(shí)間的推移,我們舊的UserInfo這個(gè)類只提供的獲取用戶名的方法,已經(jīng)沒法滿足需求,我們同時(shí)需要獲取用戶的年齡等信息。
  • 為了不改變原本UserInfo這個(gè)類,我們就繼承UserInfo,建立一個(gè)UserInfoAdapter類,實(shí)現(xiàn)getAge獲取年齡這樣的方法。
  • 在我們的MyNewObject新的類中,我們實(shí)例化UserInfoAdapter,打印出用戶姓名和年齡。
  • 這樣,隨著我們的擴(kuò)展,我們沒有改變原先UserInfo這個(gè)類和使用這個(gè)類的接口,我們通過適配的方法,將UserInfo類擴(kuò)展出來

代碼實(shí)現(xiàn)過程如下:

<?php
//早期的一個(gè)用戶類,只實(shí)現(xiàn)獲取用戶名的方法
class UserInfo {
    public function getUserName() {
        return 'initphp';
    }
}

//MyOldObject類,從UserInfo類中獲取信息,輸出用戶名
<?php
include_once("UserInfo.php");
class MyOldObject {
    public function write() {
        $UserInfo = new UserInfo;
        echo $UserInfo->getUserName();
    }
}
$a = new MyOldObject;
$a->write();

上述代碼是早期的時(shí)候,我們使用的案例。然而UserInfoAdapter類,隨著時(shí)間推移,項(xiàng)目需求在變化,UserInfo類無法滿足需求,我們做了UserInfo類的適配器,滿足新功能的需求,如下:

<?php
include_once("UserInfo.php");
class UserInfoAdapter extends UserInfo{
    public function getUserAge() {
        return 28;
    }
    public function getUser() {
        return array(
            'username' => $this->getUserName(),
            'age' => $this->getUserAge()
        );
    }
}

MyNewObject類,新功能的類,需要打印出用戶年齡和姓名,UserInfo類無法滿足需求,需要調(diào)用UserInfoAdapter適配器這個(gè)類,如下:

<?php
include_once("UserInfoAdapter.php");
class MyNewObject {
    public function write() {
        $UserInfoAdapter = new UserInfoAdapter;
        print_r($UserInfoAdapter->getUser());
    }
}
$a = new MyNewObject;
$a->write();

大概了解了哈,接下來咱們通過一個(gè)故事來了解下。

開始的時(shí)候,黑棗玩具公司專門生產(chǎn)玩具,生產(chǎn)的玩具不限于狗、貓、獅子,魚等動(dòng)物,并且每個(gè)玩具都可以進(jìn)行“張嘴”與“閉嘴”操作,分別調(diào)用了openMouth與closeMouth方法。在這個(gè)時(shí)候,黑棗玩具公司的程序猿就定義一個(gè)抽象類Toy,甚至是接口Toy,完事其他的類去繼承父類,實(shí)現(xiàn)父類的方法,很和諧的是吧。

后來,為了擴(kuò)大業(yè)務(wù),也因?yàn)榧t棗遙控公司可以使用遙控設(shè)備對動(dòng)物進(jìn)行嘴巴控制,黑棗玩具公司打算與紅棗遙控公司合作。不過,麻煩的是,紅棗遙控公司的遙控設(shè)備是調(diào)用的動(dòng)物的doMouthOpen及doMouthClose方法。所以,黑棗玩具公司的程序員現(xiàn)在必須要做的是對Toy系列類進(jìn)行升級改造,使Toy能調(diào)用doMouthOpen及doMouthClose方法。

在考慮實(shí)現(xiàn)的方法時(shí),黑棗玩具公司的程序猿可以再在他們的父類子類里給紅棗遙控公司添加這么兩個(gè)方法就好啦。但是,當(dāng)黑棗玩具公司的程序猿一次又一次在父類子類里面重復(fù)添加著這兩個(gè)方法的時(shí)候,總會(huì)想著如此重復(fù)的工作,難道不能解決么?當(dāng)有數(shù)百個(gè)子類的時(shí)候,程序員會(huì)改瘋的。程序員往往比的是誰在不影響效率的時(shí)候更會(huì)“偷懶”,這樣做下去程序員會(huì)覺得自己很傻。

咱也不廢話了,先來看下最開始的時(shí)候的代碼:

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";
  }
}

完事,因?yàn)榫G棗遙控公司遙控設(shè)備更便宜穩(wěn)定,所以黑棗玩具公司又打算要與綠棗遙控公司合作。

不過綠棗遙控公司的遙控設(shè)備是調(diào)用的動(dòng)物的operMouth(type)方法來實(shí)現(xiàn)嘴巴控制。如果type)方法來實(shí)現(xiàn)嘴巴控制。如果type為0則“閉嘴”,反之張嘴。這下好了,程序員又得對Toy及其子類進(jìn)行升級,使Toy能調(diào)用operMouth()方法。

在這個(gè)時(shí)候,程序員必須要?jiǎng)幽X子想辦法了,就算自己勤快,萬一哪天紫棗青棗黃棗山棗這些遙控公司全來的時(shí)候,忽略自己不斷增多的工作量不說,這個(gè)Toy類可是越來越大,總有一天程序員不崩潰,系統(tǒng)也會(huì)崩潰的。

那么,問題出在哪里呢?

其實(shí)就是一開始的代碼設(shè)計(jì)實(shí)現(xiàn)違反了“開-閉”原則,也就是一個(gè)軟件實(shí)體應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉。也就是說,在設(shè)計(jì)一個(gè)模塊的時(shí)候,應(yīng)當(dāng)使這個(gè)模塊可以在不被修改的前提下被擴(kuò)展。也就是說每個(gè)尸體都是一個(gè)小王國,你讓我參與你的事情這個(gè)可以,但你不能修改我的內(nèi)部,除非我的內(nèi)部代碼確實(shí)可以優(yōu)化。

來看下最后的結(jié)果:

<?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";
  }
}
//目標(biāo)角色:紅棗遙控公司
interface RedTarget
{
  public function doMouthOpen();
  public function doMouthClose();
}
//目標(biāo)角色:綠棗遙控公司及
interface GreenTarget
{
  public function operateMouth($type = 0);
}
//類適配器角色:紅棗遙控公司
class RedAdapter implements RedTarget
{
  private $adaptee;
  function __construct(Toy $adaptee)
  {
    $this->adaptee = $adaptee;
  }
  //委派調(diào)用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;
  }
  //委派調(diào)用Adaptee:GreenTarget的operateMouth方法
  public function operateMouth($type = 0)
  {
    if ($type) {
      $this->adaptee->openMouth();
    } else {
      $this->adaptee->closeMouth();
    }
  }
}
class testDriver
{
  public function run()
  {
     //實(shí)例化一只狗玩具
    $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();

大概了解了使用方式之后,我們來看下適配器模式之中的主要角色:

  1. 目標(biāo)(Target)角色:定義客戶端使用的與特定領(lǐng)域相關(guān)的接口,這也就是我們所期待得到的
  2. 源(Adaptee)角色:需要進(jìn)行適配的接口
  3. 適配器(Adapter)角色:對Adaptee的接口與Target接口進(jìn)行適配;適配器是本模式的核心,適配器把源接口轉(zhuǎn)換成目標(biāo)接口,此角色為具體類

使用場景如下:

   1、你想使用一個(gè)已經(jīng)存在的類,而它的接口不符合你的需求
   2、你想創(chuàng)建一個(gè)可以復(fù)用的類,該類可以與其他不相關(guān)的類或不可預(yù)見的類協(xié)同工作
   3、你想使用一個(gè)已經(jīng)存在的子類,但是不可能對每一個(gè)都進(jìn)行子類化以匹配它們的接口。對象適配器可以適配它的父類接口(僅限于對象適配器)

再來看下類適配器和對象適配器的一些解釋和區(qū)別:

類適配器:Adapter與Adaptee是繼承關(guān)系

   1、用一個(gè)具體的Adapter類和Target進(jìn)行匹配。結(jié)果是當(dāng)我們想要一個(gè)匹配一個(gè)類以及所有它的子類時(shí),類Adapter將不能勝任工作
   2、使得Adapter可以重定義Adaptee的部分行為,因?yàn)锳dapter是Adaptee的一個(gè)子集
   3、僅僅引入一個(gè)對象,并不需要額外的指針以間接取得adaptee

對象適配器:Adapter與Adaptee是委托關(guān)系

   1、允許一個(gè)Adapter與多個(gè)Adaptee同時(shí)工作。Adapter也可以一次給所有的Adaptee添加功能
   2、使用重定義Adaptee的行為比較困難

再來看下其它和適配器模式的對比:

  1. 橋梁模式(bridge模式):橋梁模式與對象適配器類似,但是橋梁模式的出發(fā)點(diǎn)不同,橋梁模式目的是將接口部分和實(shí)現(xiàn)部分分離,從而對它們可以較為容易也相對獨(dú)立的加以改變。而對象適配器模式則意味著改變一個(gè)已有對象的接口
  2. 裝飾器模式(decorator模式):裝飾模式增強(qiáng)了其他對象的功能而同時(shí)又不改變它的接口。因此裝飾模式對應(yīng)用的透明性比適配器更好。

最后來看下類適配器和對象適配器案例,如下:

//類適配器使用的是繼承
<?php
/**
 * 目標(biāo)角色
 */
interface Target {
 /**
  * 源類也有的方法1
  */
 public function sampleMethod1();
 /**
  * 源類沒有的方法2
  */
 public function sampleMethod2();
}
/**
 * 源角色
 */
class Adaptee {
 /**
  * 源類含有的方法
  */
 public function sampleMethod1() {
  echo 'Adaptee sampleMethod1 <br />';
 }
}
/**
 * 類適配器角色
 */
class Adapter extends Adaptee implements Target {
 /**
  * 源類中沒有sampleMethod2方法,在此補(bǔ)充
  */
 public function sampleMethod2() {
  echo 'Adapter sampleMethod2 <br />';
 }
}
class Client {
 /**
  * Main program.
  */
 public static function main() {
  $adapter = new Adapter();
  $adapter->sampleMethod1();
  $adapter->sampleMethod2();
 }
}
Client::main();
?>

//對象適配器使用的是委派
<?php
/**
 * 目標(biāo)角色
 */
interface Target {
 /**
  * 源類也有的方法1
  */
 public function sampleMethod1();
 /**
  * 源類沒有的方法2
  */
 public function sampleMethod2();
}
/**
 * 源角色
 */
class Adaptee {
 /**
  * 源類含有的方法
  */
 public function sampleMethod1() {
  echo 'Adaptee sampleMethod1 <br />';
 }
}
/**
 * 類適配器角色
 */
class Adapter implements Target {
 private $_adaptee;
 public function __construct(Adaptee $adaptee) {
  $this->_adaptee = $adaptee;
 }
 /**
  * 委派調(diào)用Adaptee的sampleMethod1方法
  */
 public function sampleMethod1() {
  $this->_adaptee->sampleMethod1();
 }
 /**
  * 源類中沒有sampleMethod2方法,在此補(bǔ)充
  */
 public function sampleMethod2() {
  echo 'Adapter sampleMethod2 <br />';
 }
}
class Client {
 /**
  * Main program.
  */
 public static function main() {
  $adaptee = new Adaptee();
  $adapter = new Adapter($adaptee);
  $adapter->sampleMethod1();
  $adapter->sampleMethod2();
 }
}
Client::main();
?>

好啦,本次記錄就到這里了。

更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》、《PHP數(shù)組(Array)操作技巧大全》、《PHP基本語法入門教程》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總

希望本文所述對大家PHP程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • PHP實(shí)現(xiàn) APP端微信支付功能

    PHP實(shí)現(xiàn) APP端微信支付功能

    這篇文章主要介紹了PHP實(shí)現(xiàn) APP端微信支付功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-06-06
  • thinkphp分頁集成實(shí)例

    thinkphp分頁集成實(shí)例

    下面小編就為大家?guī)硪黄猼hinkphp分頁集成實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • 回帖的圖片實(shí)現(xiàn)代碼

    回帖的圖片實(shí)現(xiàn)代碼

    其實(shí)原理就是通過php的session判斷,發(fā)帖前后不同的session值進(jìn)行判斷,需要的朋友可以自由發(fā)揮下
    2014-02-02
  • PHP單鏈表的實(shí)現(xiàn)代碼

    PHP單鏈表的實(shí)現(xiàn)代碼

    單鏈表是一種鏈?zhǔn)酱嫒〉臄?shù)據(jù)結(jié)構(gòu),用一組地址任意的存儲(chǔ)單元存放線性表中的數(shù)據(jù)元素。接下來通過本文給大家分享php單鏈表的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看下吧
    2016-07-07
  • php實(shí)現(xiàn)頭像上傳預(yù)覽功能

    php實(shí)現(xiàn)頭像上傳預(yù)覽功能

    這篇文章主要為大家詳細(xì)介紹了php實(shí)現(xiàn)頭像上傳預(yù)覽功能的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • php切割頁面div內(nèi)容的實(shí)現(xiàn)代碼分享

    php切割頁面div內(nèi)容的實(shí)現(xiàn)代碼分享

    今天在百度知道看到一個(gè)關(guān)于php獲取DIV內(nèi)容的問題,做了一晚,終于是做出來了
    2012-07-07
  • Thinkphp搜索時(shí)首頁分頁和搜索頁保持條件分頁的方法

    Thinkphp搜索時(shí)首頁分頁和搜索頁保持條件分頁的方法

    這篇文章主要介紹了Thinkphp搜索時(shí)首頁分頁和搜索頁保持條件分頁的方法,以兩種不同的方式詳細(xì)分析了實(shí)現(xiàn)搜索時(shí)分頁情況下保持搜索條件的方法,是非常具有實(shí)用價(jià)值的技巧,需要的朋友可以參考下
    2014-12-12
  • PHP實(shí)現(xiàn)chrome表單請求數(shù)據(jù)轉(zhuǎn)換為接口使用的json數(shù)據(jù)

    PHP實(shí)現(xiàn)chrome表單請求數(shù)據(jù)轉(zhuǎn)換為接口使用的json數(shù)據(jù)

    這篇文章主要介紹了PHP實(shí)現(xiàn)chrome表單請求數(shù)據(jù)轉(zhuǎn)換為接口使用的json數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • PHP用戶注冊郵件激活賬戶的實(shí)現(xiàn)代碼

    PHP用戶注冊郵件激活賬戶的實(shí)現(xiàn)代碼

    我們在注冊一個(gè)網(wǎng)站的賬戶時(shí),通常都會(huì)收到一封含點(diǎn)擊鏈接激活的郵件,本篇文章主要介紹了PHP郵件激活賬戶的實(shí)現(xiàn)代碼,有興趣的可以了解一下
    2017-05-05
  • PHP按符號截取字符串的指定部分的實(shí)現(xiàn)方法

    PHP按符號截取字符串的指定部分的實(shí)現(xiàn)方法

    字符串截取在php開發(fā)中是比較常用的,而且對于截取的需求也多種多樣,這篇文章主要介紹了PHP按符號截取字符串的指定部分 ,需要的朋友可以參考下
    2018-09-09

最新評論

黄骅市| 那曲县| 阿拉尔市| 方正县| 吴江市| 盐津县| 巩留县| 湄潭县| 巴青县| 馆陶县| 临高县| 进贤县| 曲阳县| 武山县| 麻江县| 长葛市| 闸北区| 和平县| 迁西县| 高淳县| 布拖县| 河北省| 牙克石市| 临高县| 澄迈县| 泾阳县| 台东市| 浮梁县| 桓仁| 伊宁县| 金川县| 临澧县| 衡阳市| 犍为县| 云阳县| 马山县| 北碚区| 海阳市| 嘉荫县| 凌海市| 孝感市|