我正在考慮我的設計模式,我在編碼中尚未認真使用的一種模式是裝飾模式。何時使用裝飾模式?
我明白這個模式,但是我很想知道的是在現實世界中的一些很好的具體例子,裝飾模式是最好的/最優的/優雅的解決方案。特定的情況下,需要裝飾模式是非常方便的。
謝謝。
我正在考慮我的設計模式,我在編碼中尚未認真使用的一種模式是裝飾模式。何時使用裝飾模式?
我明白這個模式,但是我很想知道的是在現實世界中的一些很好的具體例子,裝飾模式是最好的/最優的/優雅的解決方案。特定的情況下,需要裝飾模式是非常方便的。
謝謝。
Decorator模式是使用了很多與流:你可以用用的流的獲取附加功能。我已經看到了.Net框架 - 據我所知,這發生在其他地方。我最喜歡在FileStream中使用GZipStream來增加壓縮。
Zend框架使用表單元素
一些更多的信息裝飾:http://framework.zend.com/manual/en/zend.form.decorators.html
是的,我可以看到如何使用它的形式元素是有道理的。我正在閱讀維基百科頁面上的類似示例:http://en.wikipedia.org/wiki/Decorator_Pattern – 2009-10-11 03:18:20
很高興看到裝飾設計模式示例,它始終不是流包裝類示例! – kta 2014-04-13 13:53:05
我最近使用的裝飾圖案,其中使用以下CommandProcessor接口的web服務:
public Command receive(Request request);
public Response execute(Command command);
public void respond(Response response);
基本上,CommandProcessor接收到一個請求,並創建正確的命令,執行命令,並創建相應的響應併發送響應。當我想添加時間並記錄它時,我創建了一個使用現有CommandProcessor作爲其組件的TimerDecorator。 TimerDecorator實現CommandProcessor接口,但只是添加時序,然後調用它的目標,這是真正的CommandProcessor。事情是這樣的:
public class TimerDecorator implements CommandProcessor {
private CommandProcessor target;
private Timer timer;
public TimerDecorator(CommandProcessor processor) {
this.target = processor;
this.timer = new Timer();
}
public Command receive(Request request) {
this.timer.start();
return this.target.receive(request);
}
public Response execute(Command command) {
return this.target.execute(command);
}
public void respond(Response response) {
this.target.response(response);
this.timer.stop();
// log timer
}
}
所以真正的CommandProcessor被包裹在裏面TimerDecorator,我可以把TimerDecorator就像目標CommandProcessor,但現在定時邏輯已被添加。
裝飾模式用於添加額外的功能到一個特定的對象,而不是一類對象。通過繼承對象來爲整個對象類添加功能是很容易的,但不可能通過這種方式擴展單個對象。使用裝飾器模式,您可以將功能添加到單個對象,並讓其他人無需修改即可。
在Java中,裝飾器模式的一個經典示例是Java I/O Streams實現。
FileReader frdr = new FileReader(filename);
LineNumberReader lrdr = new LineNumberReader(frdr);
前面的代碼創建的讀取器 - lrdr
- 即從一個文件,音軌行號讀取。第1行創建文件閱讀器(frdr
),第2行添加行號跟蹤。
其實,我強烈建議您查看Java I/O類的Java源代碼。
裝飾器很簡單但非常強大。這是實現問題分離的關鍵,也是開放封閉原則的重要工具。以訂貨爲產品的一個常見的例子:
IOrderGateway
{
void PlaceOrder(Order order);
{
主要實現:AmazonAffiliateOrderGateway
可能的裝飾可能是:
IncrementPerformanceCounterOrderGateway
QueueOrderForLaterOnTimeoutOrderGateway
EmailOnExceptionOrderGateway
InterceptTestOrderAndLogOrderGateway
有關更詳細的示例,請參閱here。
Decorator模式在運行時動態更改對象的功能而不會影響對象的現有功能。
關鍵用例:
缺點:
現實世界的例子:計算飲料的價格,其中可能包含多種口味。
abstract class Beverage {
protected String name;
protected int price;
public Beverage(){
}
public Beverage(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
protected void setPrice(int price){
this.price = price;
}
protected int getPrice(){
return price;
}
protected abstract void decorateBeverage();
}
class Tea extends Beverage{
public Tea(String name){
super(name);
setPrice(10);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
class Coffee extends Beverage{
public Coffee(String name){
super(name);
setPrice(15);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
abstract class BeverageDecorator extends Beverage {
protected Beverage beverage;
public BeverageDecorator(Beverage beverage){
this.beverage = beverage;
setName(beverage.getName()+"+"+getDecoratedName());
setPrice(beverage.getPrice()+getIncrementPrice());
}
public void decorateBeverage(){
beverage.decorateBeverage();
System.out.println("Cost of:"+getName()+":"+getPrice());
}
public abstract int getIncrementPrice();
public abstract String getDecoratedName();
}
class SugarDecorator extends BeverageDecorator{
public SugarDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateSugar();
}
public void decorateSugar(){
System.out.println("Added Sugar to:"+beverage.getName());
}
public int getIncrementPrice(){
return 5;
}
public String getDecoratedName(){
return "Sugar";
}
}
class LemonDecorator extends BeverageDecorator{
public LemonDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateLemon();
}
public void decorateLemon(){
System.out.println("Added Lemon to:"+beverage.getName());
}
public int getIncrementPrice(){
return 3;
}
public String getDecoratedName(){
return "Lemon";
}
}
public class VendingMachineDecorator {
public static void main(String args[]){
Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();
beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();
}
}
輸出:
Cost of:Assam Tea:10
Cost of:Assam Tea+Lemon:13
Added Lemon to:Assam Tea
Cost of:Assam Tea+Lemon+Sugar:18
Added Sugar to:Assam Tea+Lemon
Cost of:Cappuccino:15
Cost of:Cappuccino+Lemon:18
Added Lemon to:Cappuccino
Cost of:Cappuccino+Lemon+Sugar:23
Added Sugar to:Cappuccino+Lemon
本例計算中增加了許多風味飲料後自動販賣機飲料的成本。
在上面的例子:
茶= 10,檸檬= 3和糖= 5的成本如果進行糖+檸檬+茶,它的成本18.
成本咖啡= 15,檸檬的= 3和Sugar = 5。如果您製作Sugar +檸檬+咖啡,則需花費23
通過對兩種飲料(茶和咖啡)使用相同的裝飾器,子類的數量已減少。在沒有Decorator模式的情況下,您應該爲不同的組合使用不同的子類。
的組合將是這樣的:
SugarLemonTea
SugarTea
LemonTea
SugarLemonCapaccuino
SugarCapaccuino
LemonCapaccuino
等
通過使用相同裝飾兩種飲料,子類的數量已經減少。這可能是由於組合而不是繼承在這種模式中使用的概念。
相關SE問題:
相關鏈接:
design-patterns-decorator通過dzone通過
decorator sourcemaking
oodesign文章
同樣,Java流只是裝飾裝飾者的巨大集合,裝飾者裝飾了裝飾物。我的臉剛好融化了。 – 2009-10-11 04:28:56
我認爲溪流會比我頭上的咖啡例子更好的例子:我書桌上的設計模式書。 – 2009-10-11 05:01:02
任何人都可以解釋爲什麼裝飾模式是這種情況的最佳解決方案? – 2016-05-13 03:59:20