如何利用裝飾者模式在不改變原有對象的基礎上擴展功能

點擊上方藍色「 方誌朋 」,選擇「設爲星標」java

回覆「666」獲取獨家整理的學習資料!面試

做者:雙子孤狼數據庫

blog.csdn.net/zwx900102/article/details/107740212緩存

閱讀目錄

  • 什麼是裝飾者模式微信

  • 普通示例數據結構

  • 裝飾者模式示例架構

  • 類圖關係併發

  • 裝飾者模式使用場景ide

  • 裝飾者模式優勢微服務

  • 裝飾者模式缺點

什麼是裝飾者模式

裝飾者模式(DecoratorPattern)是指在不改變原有對象的基礎之上,將功能附加到對
象上,提供了比繼承更有彈性的替代方案(擴展原有對象的功能),屬於結構型模式。

裝飾者模式在生活中也有不少形象的例子,好比說給蛋糕加上一些水果,給披薩加上榴蓮,或者說給燒餅加上雞蛋火腿之類等等。

下面咱們就以給蛋糕加上水果爲例來看看若是不用裝飾者模式要怎麼實現,若是使用裝飾者模式又要怎麼實現,對比以後就知道裝飾者模式的優點了。

普通示例

新建一個普通的蛋糕類:

package com.zwx.design.pattern.decorator.common;

import java.math.BigDecimal;

public class Cake {

    public String getCakeMsg(){
        return "我是一個8英寸的普通蛋糕";
    }

    public BigDecimal getPrice(){
        return new BigDecimal("68");
    }
}

這時候,咱們須要給蛋糕加點芒果,那能夠再新建一個類去繼承普通Cake類,而後重寫其中的方法:

package com.zwx.design.pattern.decorator.common;

import java.math.BigDecimal;

public class CakeAddMango extends Cake {
    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + "+1個芒果";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("10"));
    }
}

這時候,若是不單單加芒果,還要再加點葡萄,那麼能夠再寫一個類,繼承CakeAddMango,而後重寫其中的方法。

package com.zwx.design.pattern.decorator.common;

import java.math.BigDecimal;

public class CakeAddMangoAndGrape extends CakeAddMango {
    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + "+1個葡萄";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("5"));
    }
}

寫個測試類測一下:

package com.zwx.design.pattern.decorator.common;

public class TestCake {
    public static void main(String[] args) {
        //普通蛋糕
        Cake cake = new Cake();
        System.out.println(cake.getCakeMsg() + ",價格:" + cake.getPrice());

        //加芒果蛋糕
        CakeAddMango cakeAddMango = new CakeAddMango();
        System.out.println(cakeAddMango.getCakeMsg() + ",價格:" + cakeAddMango.getPrice());

        //加芒果和葡萄蛋糕
        CakeAddMangoAndGrape cakeAddMangoAndGrape = new CakeAddMangoAndGrape();
        System.out.println(cakeAddMangoAndGrape.getCakeMsg() + ",價格:" + cakeAddMangoAndGrape.getPrice());
    }
}

輸出以下結果:

我是一個8英寸的普通蛋糕,價格:68
我是一個8英寸的普通蛋糕+1個芒果,價格:78
我是一個8英寸的普通蛋糕+1個芒果+1個葡萄,價格:83

看起來挺好的,能實現,可是假如咱們加2個芒果呢?或者是我要加2個普通呢,或者說芒果和葡萄要組合,數量不必定,那利用現有的類是沒法實現的,只能不斷加類去重寫,若是業務變動頻繁,修改起來會是致命的。

正由於普通的實現方法有這種缺陷,纔有了裝飾者模式,接下來咱們來看看同一個需求利用裝飾者模式是怎麼實現的吧。

往期面試題:001期~180期彙總

裝飾者模式示例

一、新建一個蛋糕的抽象類:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public abstract class Cake {
    public abstract String getCakeMsg();

    public abstract BigDecimal getPrice();
}

二、而後新建一個普通蛋糕的類:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public class BaseCake extends Cake {
    @Override
    public String getCakeMsg() {
        return "我是一個8英寸的普通蛋糕";
    }

    @Override
    public BigDecimal getPrice() {
        return new BigDecimal("68");
    }
}

三、新建一個蛋糕的裝飾器類,內部持有蛋糕Cake對象,這個就是擴展的關鍵:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public abstract class CakeDecorator extends Cake{
    private Cake cake;

    public CakeDecorator(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getCakeMsg() {
        return this.cake.getCakeMsg();
    }

    @Override
    public BigDecimal getPrice() {
        return this.cake.getPrice();
    }
}

四、新建一個芒果蛋糕的裝飾器類繼承CakeDecorator類:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public class CakeAddGrapeDecorator extends CakeDecorator {
    public CakeAddGrapeDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + "+1個葡萄";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("5"));
    }
}

五、新建一個葡萄的裝飾器類繼承CakeDecorator類:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public class CakeAddMangoDecorator extends CakeDecorator {

    public CakeAddMangoDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + "+1個芒果";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("10"));
    }
}

六、最後寫一個測試類測試一下:

package com.zwx.design.pattern.decorator;

public class TestCakeDecorator {
    public static void main(String[] args) {
        Cake cake = null;
        //普通蛋糕
        cake = new BaseCake();
        System.out.println(cake.getCakeMsg() + ",價格:" + cake.getPrice());
        //加一個芒果
        cake = new CakeAddMangoDecorator(cake);
        System.out.println(cake.getCakeMsg() + ",價格:" + cake.getPrice());
        //加一個葡萄
        cake = new CakeAddGrapeDecorator(cake);
        System.out.println(cake.getCakeMsg() + ",價格:" + cake.getPrice());
        //再加一個芒果
        cake = new CakeAddMangoDecorator(cake);
        System.out.println(cake.getCakeMsg() + ",價格:" + cake.getPrice());
    }
}

輸出結果爲:

我是一個8英寸的普通蛋糕,價格:68
我是一個8英寸的普通蛋糕+1個芒果,價格:78
我是一個8英寸的普通蛋糕+1個芒果+1個葡萄,價格:83
我是一個8英寸的普通蛋糕+1個芒果+1個葡萄+1個芒果,價格:93

咱們能夠看到,使用裝飾者模式以後,擴展以前的功能變得極爲方便,能夠根據現有的裝飾器進行任意組合。

類圖關係

看一下類圖,首先是一個基礎抽象類定義了基本方法,而後是基礎實現和基礎裝飾器繼承並重寫抽象類中的方法:

裝飾者模式使用場景

  • 一、用於擴展一個類的功能或給一個類添加附加職責。

  • 二、動態的給一個對象添加功能,這些功能能夠再動態的撤銷。

注:MyBatis中的二級緩存就是用了裝飾者模式來進行動態擴展,感興趣的能夠去了解下。

往期面試題:001期~180期彙總

裝飾者模式優勢

  • 一、裝飾者是繼承的有力補充,比繼承靈活,不改變原有對象的狀況下動態地給一個對象 擴展功能,即插即用。

  • 二、經過使用不一樣裝飾類以及這些裝飾類的排列組合,能夠實現不一樣效果。

  • 三、裝飾者徹底遵照開閉原則。

裝飾者模式缺點

  • 一、會出現更多的代碼,更多的類,增長程序複雜性。

  • 二、動態裝飾以及多層裝飾時會更加複雜。

 

 
  

熱門內容:

最近面試BAT,整理一份面試資料Java面試BAT通關手冊,覆蓋了Java核心技術、JVM、Java併發、SSM、微服務、數據庫、數據結構等等。

獲取方式:點「在看」,關注公衆號並回復 666 領取,更多內容陸續奉上。

明天見(。・ω・。)ノ♡

本文分享自微信公衆號 - 方誌朋(walkingstory)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索