2017-04-22 66 views
7

從「頭先:設計模式」書中的裝飾模式用例使我有這個問題。我會盡力把它寫下來:使用列表而不是裝飾模式?

這是一個咖啡廳系統與一些咖啡和大量的調味品 你可以把它們(需支付額外費用),你需要能夠訂購 和爲了避免產生總的混亂(例如布爾值來追蹤 調味品),使用Decorator Pattern來裝飾任何調味品的咖啡。我們有一個抽象的飲料 類,每種類型的咖啡,混凝土構件和各調味品 混凝土裝飾包裹起來的飲料,如:

Beverage Class Diagram

因此,我們有以下過程返回咖啡成本:

Coffee Cost Delegation

我的問題是:爲什麼不使用列表,而不是裝飾實現這個?我們可以在每個飲料中列出調味品列表,並通過遍歷列表來計算成本。要訂購的咖啡,我們就只需要一次實例並添加所需的調味品,避免類似的聲明:

// Using second image example 
Beverage beverage = new DarkRoast(beverage); 
beverage = new Mocha(beverage); 
beverage = new Whip(beverage); 

此外,我們將有想放棄的折扣,咖啡不包括它的調味品操作更加靈活,一旦我們不會讓裝飾者包裝咖啡。這是一個長期研究的問題,我知道我錯過了一些東西,或者我錯了,所以如果你對此有任何想法,我很想知道並進一步討論它。

+0

這不是關於折扣或稅款清單,您必須扣除或按成本添加。這是關於您使用裝飾模式處理的行爲。而且,相信我,用列表而不是繼承來處理這些行爲是很困難的。 – freedev

+0

你能用這個案例舉個例子嗎?或者可能是另一個隨機情況我真的無法想象發生這種情況的情況。 – Paternostro

+4

這似乎是一個更好的[softwareengineering.stackexchange.com](https://softwareengineering.stackexchange.com)的問題。就我個人而言,我認爲這是Decorator的一個可怕的用法(維基百科也有類似的例子,我認爲),絕對可以用一個更易於管理的方式用列表解決。 'java.io.InputStream'是裝飾器的一個例子,它運行良好。但是,您已經可以看到有一位用戶不同意我的觀點,這就是爲什麼這可能與SO無關。 – Radiodef

回答

1

您應該區分數據和行爲。

裝飾器是一個間接處理一個非常具體的問題層。數據(根據類型,合同,協議等)保持不變,但您在實施方面獲得更多靈活性。使用裝飾器,您可以重新使用現有功能並開始添加更改 - 與適配器配合使用後,您可以慢慢地從pone API遷移到其他適配器並保持兼容。

列表只應該負責以特定方式訪問所包含的數據。對數據執行任務/處理列表中包含的數據應該由具有不同職責的函數/對象/類完成。

+0

最後一段對我來說沒有意義。 _handling data_如何不在其上執行任務? –

+0

我有一點更具體。 –

1

您所講的是一種計算飲料總成本的方法。更籠統地說,您提出了一種替代方法來合併&,通過將它們添加到列表中來執行Decorator模式假定的每個派生對象的主要行爲。這也不是一個面向對象的方法。

但是Decorator Pattern的原意去了更廣泛的視角,除此之外。它是動態添加擴展功能到對象。這意味着我有一些對象O1 &我希望它將其轉換成另一個對象O2具有擴展功能&還沒有那些2是可以互換的。

所以這是我們如何能夠管理對象演進Object Lifecycle。希望你明白了。 :))

1

Decorator模式是關於在運行時使用附加功能裝飾(增強)對象。

假設你已經有一個類,我們稱之爲A類,它實現了一個接口IA。現在,如果需要添加一個我們希望它有一個方法的附加功能,someAlignFeatureToA()這在A中不存在。現在您可以選擇擴展類A。另一種方法是Composition,應該比Inheritance更受青睞。您可以將A類別的對象包裝到另一個類別B中,並且AIA表示相同Interface。這種方式對於客戶端代碼來說很容易接受類B的對象,因爲它具有與A相同的接口。(假設代碼寫得很好,取決於抽象(接口IA),而不是具體的類類別A)。

這樣,繼承鏈不會太長,您可以輕鬆地在runtimw中添加其他功能。