裝飾者模式(Decorator) 結構型

2021-10-09 13:34:06 字數 4275 閱讀 5800

1 基礎知識

定義:在不改變原有物件的基礎上,將功能附加到物件上即動態地給乙個物件新增一些額外的職責。特徵:提供了比繼承更有彈性的替代方案。

本質:動態組合。

使用場景:擴充套件乙個類的功能或給乙個類新增附加的職責;動態給乙個物件新增功能,這些功能還可以動態撤銷。

優點:比繼承更加靈活,繼承是靜態的在設計之初就確定好了而裝飾者是動態的擴充套件功能;通過使用不同的裝飾類或裝飾類的排列組合可以達到不同的效果;符合開閉原則。缺點:會出現更多的**,更多的類使程式複雜;動態裝飾時,多層裝飾會更複雜。

2 **示例

場景:設若有乙個計算獎金的物件,現在需要能夠靈活地給它增加和減少功能,還需要能夠動態地組合功能,每個功能就相當於在計算獎金的某個部分。現在的問題就是,如何才能夠透明地給乙個物件增加功能,並實現功能的動態組合?在此種情況下可以用到裝飾者模式,所謂透明增加功能就是給乙個物件增加功能但是不能讓物件知道。在使用時可以考慮乙個更為簡單的場景:假設商家做了許多煎餅,這些煎餅有的加蛋,有的加烤腸那麼如何計算出這些不同種類的的煎餅?

煎餅類:battercake 

public class battercake 

//煎餅的基本**

protected int cost()

}

煎餅加雞蛋類:battercakewithegg 繼承煎餅類

public class battercakewithegg extends battercake 

@override

//重寫父類花費方法

public int cost()

}

煎餅加雞蛋類加香腸類:battercakewitheggsausage  繼承煎餅加雞蛋類

public class battercakewitheggsausage extends battercakewithegg 

@override

public int cost()

}

應用層:test 

public class test 

}

此時如果想加兩個雞蛋,加三個香腸等則需要分別建立對應的類這樣可以預見一定會隨著的需求的複雜而使得的類的數目上公升,造成類**。那麼對於這種情形的解決方案便是裝飾者模式。在裝飾者模式中要有抽象的實體類、具體的實體類,抽象的裝飾者、具體的裝飾者根據這些來編寫**。

抽象的實體類:abattercake

public abstract class abattercake
具體的實體類煎餅類:battercake 繼承抽象實體類

public class battercake extends abattercake 

@override

protected int cost()

}

抽象的裝飾類:abstractdecorator

//抽象的裝飾者繼承了抽象的實體

public abstract class abstractdecorator extends battercake

protected abstract void dosomething();

@override

protected string getdesc()

@override

protected int cost()

}

具體的裝飾類香腸類:sausagedecorator 繼承抽象裝飾者

public class sausagedecorator extends abstractdecorator

@override

protected void dosomething()

@override

protected string getdesc()

@override

protected int cost()

}

具體的裝飾者類雞蛋類:eggdecorator

public class eggdecorator extends abstractdecorator 

@override

protected void dosomething()

@override

protected string getdesc()

@override

protected int cost()

}

應用層:

public class test 

}

類關係圖:

注:

在抽象的裝飾類中有乙個dosomething方法,這個方法在這個業務邏輯中只是為了讓裝飾類是抽象的而已並無任何業務邏輯,從這裡也可以看出抽象的裝飾類在不同的業務情況下也可以不是抽象的。

3 源**中的使用

(1)jdk中

io包下的bufferedreader類:

public class bufferedreader extends reader
reader是乙個抽象的類,就相當於抽象的煎餅類,bufferedreader上面中的抽象的裝飾者類,通過構造器注入reader物件,在這裡承擔抽象裝飾者類的角色但不是抽象類。

在io流中對於輸入流其類圖關係如下:

inputstream就是抽象的裝飾者類,filterinputstream是裝飾者,但因為裝飾者比較多因此做了一層封裝,下面的lineinputstream、bufferdinputstream和datainputstream是具體的裝飾者。與此類似的還有輸出流中的類outputstream。

4 相關模式

(1)裝飾模式與介面卡模式

(2)裝飾模式與組合模式

這兩個模式有相似之處,都涉及到物件的遞迴呼叫,從某個角度來說,可以把裝飾看做是只有乙個元件的組合。但是它們的目的完全不一樣,裝飾模式是要動態地給物件增加功能;而組合模式是想要管理組合物件和葉子物件,為它們提供乙個一致的操作介面給客戶端,方便客戶端的使用。

(3)裝飾模式與策略模式

這兩個模式可以組合使用。策略模式也可以實現動態地改變物件的功能,但是策略模式只是一層選擇,也就是根據策略選擇一下具體的實現類而已。而裝飾模式不是一層,而是遞迴呼叫,無數層都可以,只要組合好裝飾器的物件組合,那就可以依次呼叫下去。所以裝飾模式更靈活。而且策略模式改變的是原始物件的功能,不像裝飾模式,後面乙個裝飾器,改變的是經過前乙個裝飾器裝飾後的物件。也就是策略模式改變的是物件的核心,而裝飾模式改變的是物件的外殼。

這兩個模式可以組合使用,可以在乙個具體的裝飾器中使用策略模式來選擇更具體的實現方式。比如前面計算獎金的另外乙個問題就是參與計算的基數不同,獎金的計算方式也是不同的。舉例來說:假設張三和李四參與同乙個獎金的計算,張三的銷售總額是2萬元,而李四的銷售總額是8萬元,它們的計算公式是不一樣的,假設獎金的計算規則是,銷售額在5萬以下,統一3%,而5萬以上,5萬內是4%,超過部分是6%參與同乙個獎金的計算,這就意味著可以使用同乙個裝飾器,但是在裝飾器的內部,不同條件下計算公式不一樣,那麼怎麼選擇具體的實現策略呢?自然使用策略模式就可以了,也就是裝飾模式和策略模式組合來使用。

(4)裝飾模式與模板方法模式

這是兩個功能上有相似點的模式。模板方法模式主要應用在演算法骨架固定的情況,那麼要是演算法步驟不固定呢,也就是乙個相對動態的演算法步驟,就可以使用裝飾模式了,因為在使用裝飾模式的時候,進行裝飾器的組裝,其實也相當於是乙個呼叫演算法步驟的組裝,相當於是乙個動態的演算法骨架。既然裝飾模式可以實現動態的演算法步驟的組裝和呼叫,那麼把這些演算法步驟固定下來,那就是模板方法模式實現的功能了,因此裝飾模式可以模擬實現模板方法模式的功能。

注意:僅僅只是可以模擬功能而已,兩個模式的設計目的功能本質等都是不一樣的。

裝飾者模式decorator

設計原則 開放 關閉原則,對擴充套件開放,對修改封閉 多用組合,少用繼承 針對介面程式設計,不針對實現程式設計 為互動物件之間的松耦合設計而努力 類圖待補充 示例 飲料銷售系統 主體飲料 coffe 輔助調料 mocha,soy,whip。輔助調料價位都不一樣,當輔助調料和主飲料不同搭配時,最終飲料...

裝飾者(Decorator)模式

裝飾者模式是允許向乙個新物件新增新的功能,但又不改變其結構。這種模式建立了乙個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。就增加功能來說,裝飾器模式相比生成子類更為靈活。例子 如果我們去咖啡店,有一種咖啡,該咖啡可以加糖,牛奶,奶泡等等,如果我們需要加糖和牛奶,常規...

裝飾者模式 Decorator

1 作用 動態的給物件增加執行的業務,不受數量限制。可以代替子類,同時避免子類與父類的高耦合。增加靈活性。2 構成 2.1 裝飾者抽象類 decorator 可以是介面 最終生成乙個指向被裝飾物件基類 component 例項的引用,並定義乙個與被裝飾物件基類 component 介面一致的介面。通...