裝飾器模式

裝飾器模式(Decorator Pattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝。
這種模式創(chuàng)建了一個(gè)裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。
我們通過下面的實(shí)例來演示裝飾器模式的用法。其中,我們將把一個(gè)形狀裝飾上不同的顏色,同時(shí)又不改變形狀類。

介紹

裝飾器實(shí)現(xiàn)修飾對(duì)象(Component)的接口,所有請(qǐng)求都轉(zhuǎn)發(fā)給它處理,在轉(zhuǎn)發(fā)請(qǐng)求之前/之后增加額外功能。使用步驟是:
用一個(gè)Decorator實(shí)現(xiàn)/繼承需要修飾的對(duì)象Component;
在Decorator中增加一個(gè)Component的引用;
在Decorator的構(gòu)造器中,增加一個(gè)Component參數(shù)來初始化Component;
在Decorator類中,使用Component的引用,將所有請(qǐng)求轉(zhuǎn)發(fā)至Component的相應(yīng)方法;
ConcreteDecorator中所有Override自Component的方法做相應(yīng)調(diào)整。
從類圖上看,裝飾器模式與代理模式很像,是它們的目的不同,所以使用方法和適用場(chǎng)景上也就不同 ,裝飾器模式與代理模式的區(qū)別:
代理模式專注于對(duì)被代理對(duì)象的訪問;
裝飾器模式專注于對(duì)被裝飾對(duì)象附加額外功能。
就像前面所說的io工具包,我用BufferedInputStream和用FileInputStream去read一個(gè)文件實(shí)際使用方式上是一樣的,能用FileInputStream.read(),就能用BufferedInputStream.read(),只不過,BufferedInputStream把FileInputStream包裝了一下,增加了一個(gè)緩存,并不控制底層FileInputStream的read()行為。

適用場(chǎng)景

運(yùn)行時(shí),你需要?jiǎng)討B(tài)地為對(duì)象增加額外職責(zé)時(shí);
當(dāng)你需要一個(gè)能夠代替子類的類,借助它提供額外方法時(shí)

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

假設(shè)我去買咖啡,首先服務(wù)員給我沖了一杯原味咖啡,我希望服務(wù)員給我加些牛奶和白糖混合入原味咖啡中。使用裝飾器模式就可以解決這個(gè)問題。
咖啡接口,定義了獲取花費(fèi)和配料的接口。

/**
 * 咖啡
 */
interface Coffee {
    /** 獲取價(jià)格 */
    double getCost();
    /** 獲取配料 */
    String getIngredients();
}

原味咖啡,實(shí)現(xiàn)Coffe接口,花費(fèi)1元,配料中,只有咖啡
/**
 * 原味咖啡
 */
class SimpleCoffee implements Coffee {

    @Override
    public double getCost() {
        return 1;
    }

    @Override
    public String getIngredients() {
        return "Coffee";
    }
}

咖啡對(duì)象的裝飾器類,同樣實(shí)現(xiàn)Coffee接口,定義一個(gè)Coffe對(duì)象的引用,在構(gòu)造器中進(jìn)行初始化。并且將getCost()和getIntegredients()方法轉(zhuǎn)發(fā)給被裝飾對(duì)象。

/**
 * 咖啡的"裝飾器",可以給咖啡添加各種"配料"
 */
abstract class CoffeeDecorator implements Coffee {
    protected final Coffee decoratedCoffee;

    /**
     * 在構(gòu)造方法中,初始化咖啡對(duì)象的引用
     */
    public CoffeeDecorator(Coffee coffee) {
        decoratedCoffee = coffee;
    }

    /**
     * 裝飾器父類中直接轉(zhuǎn)發(fā)"請(qǐng)求"至引用對(duì)象
     */
    public double getCost() {
        return decoratedCoffee.getCost();
    }

    public String getIngredients() {
        return decoratedCoffee.getIngredients();
    }
}


具體的裝飾器類,負(fù)責(zé)往咖啡中“添加”牛奶,注意看getCost()方法和getIngredients()方法,可以在轉(zhuǎn)發(fā)請(qǐng)求之前或者之后,增加功能。如果是代理模式,這里的結(jié)構(gòu)就有所不同,通常代理模式根據(jù)運(yùn)行時(shí)的條件來判斷是否轉(zhuǎn)發(fā)請(qǐng)求。
/**
 * 此裝飾類混合"牛奶"到原味咖啡中
 */
class WithMilk extends CoffeeDecorator {

    public WithMilk(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double getCost() {
        double additionalCost = 0.5;
        return super.getCost() + additionalCost;
    }

    @Override
    public String getIngredients() {
        String additionalIngredient = "milk";
        return super.getIngredients() + ", " + additionalIngredient;
    }
}

另一個(gè)具體裝飾器類,用來給咖啡加糖,一樣的邏輯。
class WithSugar extends CoffeeDecorator {

    public WithSugar(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 1;
    }

    @Override
    public String getIngredients() {
        return super.getIngredients() + ", Sugar";
    }
}

客戶端使用裝飾器模式,是不是與java中的io使用方式很像?
public class DecoratorDemo {

    static void print(Coffee c) {
        System.out.println("花費(fèi)了: " + c.getCost());
        System.out.println("配料: " + c.getIngredients());
        System.out.println("============");
    }

    public static void main(String[] args) {
        //原味咖啡
        Coffee c = new SimpleCoffee();
        print(c);

        //增加牛奶的咖啡
        c = new WithMilk(c);
        print(c);

        //再加一點(diǎn)糖
        c = new WithSugar(c);
        print(c);
    }
}





?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 定義 裝飾器模式又名包裝(Wrapper)模式。裝飾器模式以對(duì)客戶端透明的方式拓展對(duì)象的功能,是繼承關(guān)系的一種替代...
    步積閱讀 36,642評(píng)論 0 38
  • 原文連接:https://www.runoob.com/design-pattern/decorator-patt...
    念?閱讀 240評(píng)論 0 0
  • Java設(shè)計(jì)模式之裝飾器模式 本文僅是個(gè)人觀點(diǎn),如有錯(cuò)誤請(qǐng)指正 簡(jiǎn)介 裝飾器模式(Decorator Patter...
    singlezero閱讀 525評(píng)論 0 0
  • 結(jié)構(gòu)型模式:把類或?qū)ο蠼Y(jié)合在一起形成一個(gè)更大的結(jié)構(gòu),即類和對(duì)象的組合。 概念 所謂裝飾器模式,就是動(dòng)態(tài)地給一個(gè)對(duì)象...
    雪飄千里閱讀 491評(píng)論 0 1
  • 1.初識(shí)裝飾模式 動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來說,裝飾模式比生成子類更為靈活。 Compone...
    王偵閱讀 802評(píng)論 0 0

友情鏈接更多精彩內(nèi)容