溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHP中的裝飾器模式是什么意思

發(fā)布時(shí)間:2021-06-24 09:36:44 來源:億速云 閱讀:150 作者:chen 欄目:編程語言

本篇內(nèi)容介紹了“PHP中的裝飾器模式是什么意思”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

裝飾器模式允許向一個(gè)現(xiàn)有的對象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。本篇文章帶大家了解PHP中的裝飾器模式,介紹一下裝飾器的好處以及最適用于的場景。

工廠模式告一段落,我們來研究其他一些模式。不知道各位大佬有沒有嘗試過女裝?據(jù)說女裝大佬程序員很多喲。其實(shí),今天的裝飾器模式就和化妝這件事很像。相信如果有程序媛MM在的話,馬上就能和你講清楚這個(gè)設(shè)計(jì)模式。

Gof類圖及解釋

裝飾這兩個(gè)字,我們暫且把他變成化妝。首先你得有一張臉,然后打底,然后上妝,可以早上來個(gè)淡妝上班,也可以下班的時(shí)候補(bǔ)成濃妝出去嗨。當(dāng)然,碼農(nóng)們下班的時(shí)間點(diǎn)正好是能趕上夜場的下半場的。話說回來,不管怎么化妝,你的臉還是你的臉,有可能可以化成別人不認(rèn)識的另一個(gè)人,但這的的確確還是你的臉。這就是裝飾器,對對象(臉)進(jìn)行各種裝飾(化妝),讓這個(gè)臉更好看(增加職責(zé))。

GoF定義:動態(tài)地給一個(gè)對象添加一些額外的職責(zé),就增加功能來說,Decorator模式相比生成子類更為靈活

GoF類圖:

PHP中的裝飾器模式是什么意思

代碼實(shí)現(xiàn):

interface Component{
    public function operation();
}

class ConcreteComponent implements Component{
    public function operation(){
        echo "I'm face!" . PHP_EOL;
    }
}

很簡單的一個(gè)接口和一個(gè)實(shí)現(xiàn),這里我們就把具體的實(shí)現(xiàn)類看作是一張臉吧!

abstract class Decorator implements Component{
    protected $component;
    public function __construct(Component $component){
        $this->component = $component;
    }
}

抽象的裝飾者類,實(shí)現(xiàn)Component接口,但并不實(shí)現(xiàn)operation()方法,讓子類去實(shí)現(xiàn)。在這里主要保存一個(gè)Componet的引用,一會就要對他進(jìn)行裝飾。對應(yīng)到上方的具體類,我們就是要準(zhǔn)備給臉化妝啦!

class ConcreteDecoratorA extends Decorator{
    public $addedState = 1; // 沒什么實(shí)際意義的屬性,只是區(qū)別于ConcreteDecoratorB

    public function operation(){
        echo $this->component->operation() . "Push " . $this->addedState . " cream!" . PHP_EOL;
    }
}
class ConcreteDecoratorB extends Decorator{
    public function operation(){
        $this->component->operation();
        $this->addedBehavior();
    }

    // 沒什么實(shí)際意義的方法,只是區(qū)別于ConcreteDecoratorA
    public function addedBehavior(){
        echo "Push 2 cream!" . PHP_EOL;
    }
}

兩個(gè)具體裝飾者。在這里我是涂了兩次霜,畢竟是純爺們,對化妝這事兒真的是不了解。好像第一步應(yīng)該先是打粉底吧?不過這次就這樣,我們這兩個(gè)裝飾器實(shí)現(xiàn)的就是給臉上涂兩層霜。

  • 從代碼中可以看出,我們是一直對具體的那個(gè)ConcreteComponent對象來進(jìn)行包裝

  • 再往下的話其實(shí)我們是對他的operation()這個(gè)方法包裝了兩次,每次都是在前一次的基礎(chǔ)上加了一點(diǎn)點(diǎn)東西

  • 不要糾結(jié)于A和B裝飾器上的added屬性和方法,他們只是GoF類圖中用以區(qū)別這兩個(gè)裝飾器不是同一個(gè)東西,每個(gè)裝飾器都可以干很多別的事,Component對象也不一定只有operation()這一個(gè)方法,我們可以選擇性的去裝飾對象中的全部或者部分方法

  • 好像我們都繼承了Component,直接子類一路重寫不就行了,搞這費(fèi)勁干嘛?親,了解下組合的概念喲,我們的Decorator父類里面是一個(gè)真實(shí)對象的引用哦,解耦了自身哦,我們只給真實(shí)的對象去做包裝,您可別直接實(shí)例化裝飾器來直接用

  • 還是沒懂?好處呢?老系統(tǒng)的類啊、方法啊你敢隨便亂改?想給前任寫的牛(S)逼(B)代碼擴(kuò)展新功能時(shí)不妨試試裝飾器這貨,說不定有奇效!

手機(jī)這玩意干不過某米、某O、某為,這沒法玩呀,好吧,哥們?nèi)P淖鍪謾C(jī)殼吧!嗯,我先準(zhǔn)備了一個(gè)透明殼(Component),貌似有點(diǎn)丑,沒辦法,誰叫哥們窮。給某米的加上各種純色(DecoratorA1),然后背后印上各種顏色的植物(DecoratorB1)吧;某O的手機(jī)最近喜歡找流量明顯做代言,那我給他的手機(jī)殼就用各種炫彩色(DecoratorA2)和明星的卡通頭像(DecoratorB2);最后的某為,好像手機(jī)已經(jīng)開始引領(lǐng)業(yè)界潮流了,折疊屏這玩意不是要砸我這賣手機(jī)殼的生意嘛?。『冒?,哥不給你們做了,還是跟我的某米、某O混去吧!!

完整代碼:裝飾器模式

https://github.com/zhangyue0503/designpatterns-php/blob/master/04.decorator/source/decorator.php

實(shí)例

繼續(xù)來發(fā)短信,之前我們用工廠模式解決了多個(gè)短信運(yùn)營商的問題。這回我們要解決的是短信內(nèi)容模板的問題。對于推廣類的短信來說,根據(jù)最新的廣告法,我們是不能出現(xiàn)“全國第一”、“全世界第一”這類的詞語的,當(dāng)然,一些不太文明的用語我們也是不能使用的。

現(xiàn)在的情況是這樣的,我們有一個(gè)很早之前的短信模板類,里面的內(nèi)容是固定的,老系統(tǒng)依然還是使用這個(gè)模板,老系統(tǒng)是面對的內(nèi)部員工,對語言內(nèi)容的要求不高。而新系統(tǒng)則需要向全網(wǎng)發(fā)送,也就是內(nèi)外部的用戶都要發(fā)送。這時(shí),我們可以用裝飾器模式來對老系統(tǒng)的短信模板進(jìn)行包裝。其實(shí)說簡單點(diǎn),我們就是用裝飾器來做文本替換的功能。好處呢?當(dāng)然是可以不去改動原來的模板類中的方法就實(shí)現(xiàn)了對老模板內(nèi)容的修改擴(kuò)展等。

短信發(fā)送類圖:

PHP中的裝飾器模式是什么意思

完整源碼:短信發(fā)送裝飾器方法

https://github.com/zhangyue0503/designpatterns-php/blob/master/04.decorator/source/message-decorator.php

<?php
// 短信模板接口
interface MessageTemplate
{
    public function message();
}

// 假設(shè)有很多模板實(shí)現(xiàn)了上面的短信模板接口
// 下面這個(gè)是其中一個(gè)優(yōu)惠券發(fā)送的模板實(shí)現(xiàn)
class CouponMessageTemplate implements MessageTemplate
{
    public function message()
    {
        return '優(yōu)惠券信息:我們是全國第一的牛X產(chǎn)品哦,送您十張優(yōu)惠券!';
    }
}

// 我們來準(zhǔn)備好裝飾上面那個(gè)過時(shí)的短信模板
abstract class DecoratorMessageTemplate implements MessageTemplate
{
    public $template;
    public function __construct($template)
    {
        $this->template = $template;
    }
}

// 過濾新廣告法中不允許出現(xiàn)的詞匯
class AdFilterDecoratorMessage extends DecoratorMessageTemplate
{
    public function message()
    {
        return str_replace('全國第一', '全國第二', $this->template->message());
    }
}

// 使用我們的大數(shù)據(jù)部門同事自動生成的新詞庫來過濾敏感詞匯,這塊過濾不是強(qiáng)制要過濾的內(nèi)容,可選擇使用
class SensitiveFilterDecoratorMessage extends DecoratorMessageTemplate
{
    public $bigDataFilterWords = ['牛X'];
    public $bigDataReplaceWords = ['好用'];
    public function message()
    {
        return str_replace($this->bigDataFilterWords, $this->bigDataReplaceWords, $this->template->message());
    }
}

// 客戶端,發(fā)送接口,需要使用模板來進(jìn)行短信發(fā)送
class Message
{
    public $msgType = 'old';
    public function send(MessageTemplate $mt)
    {
        // 發(fā)送出去咯
        if ($this->msgType == 'old') {
            echo '面向內(nèi)網(wǎng)用戶發(fā)送' . $mt->message() . PHP_EOL;
        } else if ($this->msgType == 'new') {
            echo '面向全網(wǎng)用戶發(fā)送' . $mt->message() . PHP_EOL;
        }

    }
}

$template = new CouponMessageTemplate();
$message = new Message();

// 老系統(tǒng),用不著過濾,只有內(nèi)部用戶才看得到
$message->send($template);

// 新系統(tǒng),面向全網(wǎng)發(fā)布的,需要過濾一下內(nèi)容哦
$message->msgType = 'new';
$template = new AdFilterDecoratorMessage($template);
$template = new SensitiveFilterDecoratorMessage($template);

// 過濾完了,發(fā)送吧
$message->send($template);

說明

  • 裝飾器的最大好處:一是不改變原有代碼的情況下對原有代碼中的內(nèi)容進(jìn)行擴(kuò)展,開放封閉原則;二是每個(gè)裝飾器完成自己的功能,單一職責(zé);三是用組合實(shí)現(xiàn)了繼承的感覺;

  • 最適用于:給老系統(tǒng)進(jìn)行擴(kuò)展

  • 要小心:過多的裝飾者會把你搞暈的

  • 不一定都是對同一個(gè)方法進(jìn)行裝飾,其實(shí)裝飾者應(yīng)該更多的用于對對象的裝飾,對對象進(jìn)行擴(kuò)展,這里我們都是針對一個(gè)方法的輸出進(jìn)行裝飾,但僅限此文,裝飾器的應(yīng)用其實(shí)更加廣泛

  • 裝飾器的特點(diǎn)是全部都繼承自一個(gè)主接口或類,這樣的好處就是返回的對象是相同的抽象數(shù)據(jù),具有相同的行為屬性,否則,就不是裝飾之前的對象,而是一個(gè)新對象了

  • 有點(diǎn)不好理解沒關(guān)系,我們這次的例子其實(shí)也很勉強(qiáng),這個(gè)設(shè)計(jì)模式在《Head First設(shè)計(jì)模式》中有提到Java的I/O系列接口是使用的這種設(shè)計(jì)模式:FileInputStream、LineNumberInputStream、BufferInputStream等

  • Laravel框架中的中間件管道,這里其實(shí)是多種模式的綜合應(yīng)用,其中也應(yīng)用到了裝飾器模式:Laravel HTTP——Pipeline 中間件裝飾者模式源碼分析

  • 另外在Laravel中,日志處理這里也是對Monolog進(jìn)行了裝飾,有興趣的同學(xué)可以去了解下

“PHP中的裝飾器模式是什么意思”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI