設計模式 - 裝飾者模式詳解

基本定義

裝飾者模式屬於結構型模式,它能夠動態的將新功能附加到對象上,同時又不改變其結構。在對象功能擴展方面,它比繼承更有彈性,裝飾者模式也體現了開閉原則(OCP)。java

模式結構

裝飾者和被裝飾者有相同的超類型,由於裝飾者和被裝飾者必須是同樣的類型,利用繼承是爲了達到類型的匹配,而不是利用繼承獲取行爲git

  • Component:裝飾者和被裝飾者共同的父類,是一個接口或者抽象類,用來定義基本行爲
  • ConcreteComponent:定義具體對象,即被裝飾者
  • Decorator:抽象裝飾者,繼承自 Component,從外類來擴展 ConcreteComponent。對於 ConcreteComponent來講,不須要知道Decorator的存在,Decorator 是一個接口或抽象類
  • ConcreteDecorator:具體裝飾者,用於擴展 ConcreteComponent

舉例說明

在咖啡店客人想點一杯加兩份糖一份牛奶的摩卡咖啡,各個商品的價格以下,咱們須要根據用戶點的咖啡、加的配料,動態的計算價格github

商品 價格
拿鐵咖啡(LatteCoffee) 4.5
摩卡咖啡(MochaCoffe) 5.5
糖(Sugar) 1.0
牛奶(Milk) 2.0

「實體類」 Coffeeide

public abstract class Coffee{
    public String des = "咖啡"; //描述
    private float price = 0.0f; //價格

    protected abstract float cost(); //計算費用
    
    //省略getter setter方法
}

「被裝飾者」LatteCoffee測試

public class LatteCoffee extends Coffee{
    public LatteCoffee() {
        setDes("拿鐵咖啡");
        setPrice(4.5f);
    }

    @Override
    protected float cost() {
        return getPrice();
    }
}

「被裝飾者」MochaCoffeethis

public class MochaCoffee extends Coffee {
    public MochaCoffee() {
        setDes("摩卡咖啡");
        setPrice(5.5f);
    }

    @Override
    protected float cost() {
        return getPrice();
    }
}

「抽象裝飾者」Decorator設計

public class Decorator extends Coffee {

    private Coffee coffee;

    public Decorator(Coffee drink) {
        this.coffee = drink;
    }

    @Override
    protected float cost() {
        return getPrice() + coffee.cost();
    }

    @Override
    public String getDes() {
        return coffee.getDes() + "加" + super.getDes();
    }
}

「具體裝飾者」SugarDecoratorcode

public class SugarDecorator extends Decorator{
    public SugarDecorator(Coffee coffee) {
        super(coffee);
        setDes("糖");
        setPrice(1.0f);
    }
}

「具體裝飾者」MilkDecorator對象

public class MilkDecorator extends Decorator{
    public MilkDecorator(Coffee coffee) {
        super(coffee);
        setDes("牛奶");
        setPrice(2.0f);
    }
}

「測試類」Client繼承

public class Client {
    /**
     * 點一杯 加兩份糖一份牛奶的摩卡咖啡
     */
    @Test
    public void test01() {
        Coffee order = new MochaCoffee();
        System.out.println(order.getDes() + ",價格:" + order.cost());
        //加兩份糖
        order = new SugarDecorator(new SugarDecorator(order));
        System.out.println(order.getDes() + ",價格:" + order.cost());
        //加一份牛奶
        order = new MilkDecorator(order);
        System.out.println(order.getDes() + ",價格:" + order.cost());
    }
}

「結果」result

摩卡咖啡,價格:5.5
摩卡咖啡加糖加糖,價格:7.5
摩卡咖啡加糖加糖加牛奶,價格:9.5

在 Java IO 流中的應用

在上圖所示的關係中

  • 實體類是 InputStream
  • 被裝飾者是FileInputStream、StringBufferInputStream、ByteArrayInputStream
  • 抽象裝飾者是FilterInputStream
  • 具體裝飾者是BufferInputStream、DataInputStream、LineNumberInputStream

具體使用以下:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\a.txt"));

裝飾者模式總結

一、利用繼承設計子類,只能在編譯時靜態決定,而且全部子類都會繼承相同的行爲;利用組合擴展對象,就能夠在運行時動態的進行擴展。

二、裝飾者和被裝飾者對象有相同的超類型,因此在任何須要原始對象(被裝飾者)的場合,均可以用裝飾過的對象代替原始對象。

三、能夠用一個或多個裝飾者包裝一個對象(被裝飾者)。

四、裝飾者能夠在所委託的裝飾者行爲以前或以後加上本身的行爲,以達到特定的目的。

五、被裝飾者能夠在任什麼時候候被裝飾,因此能夠在運行時動態地、不限量地用你喜歡的裝飾者來裝飾對象。

六、裝飾者會致使出現不少小對象,若是過分使用,會讓程序變得複雜。

p.s. 全部代碼和筆記都可在 個人GitHub 中獲取,若是對您有幫助的話,能夠點個 star 支持一下 🙈

相關文章
相關標籤/搜索