2010-01-30 67 views
1

是否可以從對象中移除裝飾器?你能刪除一個裝飾器嗎?

說我有下面的代碼:

abstract class Item 
{ 
    decimal cost(); 
} 

class Coffee : Item 
{ 
    decimal cost() 
    { // some stuff } 
} 

abstract class CoffeeDecorator : Item 
{ 
    Item decoratedItem; 
} 

class Mocha : CoffeeDecorator 
{ 
    Item decoratedItem; 

    public Mocha(Coffee coffee) 
    { 
     decoratedItem = coffee; 
    } 
} 

public void Main(string[] args) 
{ 
    Item coffeeDrink = new Mocha(new Coffee()); 
} 

有沒有辦法從我的新的「咖啡」對象中刪除了「新摩卡()」?

編輯:澄清 - 我想能夠刪除只是一個裝飾器,不是所有的人。所以如果我在Coffee對象上有一個Mocha裝飾器和一個Sugar裝飾器,我想知道是否可以移除「Mocha」裝飾器。

回答

3

首先,這種分配是不合法的:

Coffee coffee = new Mocha(new Coffee()); 

一個Mocha不是Coffee也沒有從MochaCoffee隱式轉換。要「移除」裝飾器,您需要提供一個方法或一個強制轉換來執行此操作。所以,你可以添加一個去除裝飾方法Mocha

public Coffee Undecorate() { 
    return (Coffee)decoratedItem; 
} 

然後,你可以說

Coffee coffee = new Mocha(new Coffee()).Undecorate(); 

或者,您可以提供在Mocha類隱式轉換操作符:

public static implicit operator Coffee(Mocha m) { 
    return (Coffee)m.decoratedItem; 
} 

然後你的線路

Coffee coffee = new Mocha(new Coffee()); 

將是合法的。

現在,您的問題暗示了對設計模式的潛在誤解(實際上,您的實現也暗示了一種誤解)。你想做的事很臭。使用裝飾器模式的正確方法就是這樣。請注意,CoffeeDecorator派生自Coffee

abstract class Item { public abstract decimal Cost(); } 
class Coffee : Item { public override decimal Cost() { return 1.99m; } } 
abstract class CoffeeDecorator : Coffee { 
    protected Coffee _coffee; 
    public CoffeeDecorator(Coffee coffee) { this._coffee = coffee; } 
} 
class Mocha : CoffeeDecorator { 
    public Mocha(Coffee coffee) : base(coffee) { } 
    public override decimal Cost() { return _coffee.Cost() + 2.79m; } 
} 
class CoffeeWithSugar : CoffeeDecorator { 
    public CoffeeWithSugar(Coffee coffee) : base(coffee) { } 
    public override decimal Cost() { return _coffee.Cost() + 0.50m; } 
} 

然後你就可以說:

Coffee coffee = new Mocha(new CoffeeWithSugar(new Coffee())); 
Console.WriteLine(coffee.Cost()); // output: 5.28 

鑑於此,你有什麼需要去除裝飾它?

+0

對不起讓我修復 – mikedev 2010-01-30 02:50:33

+0

我應該澄清 - 我想刪除只有一個裝飾器,例如,如果我有3個不同的裝飾器,我想最終只有2.你的解決方案看起來像它是刪除所有裝飾器。 – mikedev 2010-01-30 02:53:40

+0

假定你有'DecoratedCoffee咖啡=新的Mocha(新的CoffeeWithSugar(新的Coffee()));'並且你有一個方法'DecoratedCoffee.Undecorate'。 「DecoratedCoffee.Undecorate」的返回類型應該是什麼?如果它是'DecoratedCoffee',那麼'新的CoffeeWithSugar(新的Coffee())的結果是什麼?Undecorate()'?它應該是'Coffee'的新實例,但它不能是因爲它的返回類型是'DecoratedCoffee'; 'DecoratedCoffee'作爲返回類型是荒謬的。所以,它應該是'咖啡',但後來'新的摩卡咖啡(新的CoffeeWithSugar(新咖啡()))。未裝飾()。未裝飾()'不可能不鑄造。 – jason 2010-01-30 03:11:37

0

如果您有更多的flexiblity代碼時,你可以

要刪除一個裝飾,unpeel他們都沒有你要離開了一個重新組合。要刪除,你需要能夠引用每一個。添加一個表達包裝裝飾的屬性,最裏面的裝飾將表示爲null。

interface IDecoratedExpressing { 
    IDecoratedExpressing InnerDecorated {get;} 
} 

然後

// NOTE: implement IDecoratedExpressing for all decorations to provide a handle. 

// Example of first: 

class Mocha : CoffeeDecorator, IDecoratedExpressing 
{ 
    Item decoratedItem; 

    // express inner 
    public IDecoratedExpressing InnerDecorated { 
     get {return decoratedItem;} 
    } 

    public Mocha(Coffee coffee) 
    { 
     decoratedItem = coffee; 
    } 

} 

也許使InnerDecorated財產設定的,所以你可以用不同的方式把他們重新走到一起(或離開一個或多個出)。這意味着你可以通過設置屬性來操作裝飾,而不僅僅是在施工時。允許靈活性。不確定這是什麼猶太教。只是在思考。

1

使用對孩子和父母項的引用可能會在某個時間壓倒一切。

另一種方法是實現一個抽象裝飾器類,其中布爾狀態將告訴你裝飾器是否必須被視爲「on」或「off」。使用抽象類將允許您將刪除裝飾器的所有邏輯放在一個位置,然後可以在所有具體裝飾器之上構建所有具體裝飾器,而不用擔心刪除。

您必須有設置爲true這個變量,如果這是你要刪除的裝飾一個刪除裝飾方法,無所謂裝飾的裝飾鏈中的位置:

public void RemoveDecorator(DECORATOR_CODES decCode) 
{ 
      if (this.Code == decCode) 
      { 
       bDecoratorRemoved = true; 
      } 
      else 
       this.ParentBevarage.RemoveDecorator(decCode); 
     } 


public float Cost() 
     { 
      if (!bDecoratorRemoved) 
       return this.ParentBevarage.Cost() + this.Price; 
      else 
       return this.ParentBevarage.Cost(); 
     } 

你並沒有真正移除裝飾器,但是你正在中和它的效果,它在內存方面並不是更高效,但是肯定會允許你移除任何裝飾器,你想要的只是幾行代碼。如果Item對象不是太多,而且他們的生命短暫,那麼它可能是值得的。

3

建立並闡明John K.所說的裝飾模式可以被認爲是一個鏈接列表 - 在這一點上添加一個setter只是自然的。

要刪除一個圖層,只需將其父鏈接的引用指向其子鏈接;或者在裝飾模式術語中,爲了移除裝飾者foo,將foo的裝飾者的裝飾對象引用指向foo的裝飾對象。

1

我將通過調用方法,以取代目前包裝對象去除裝飾,我的意思是,如果我有裝飾ABCDE,則意味着E包裹D它包裝C它包裝B它包裝A。因此,通過調用一個方法並替換被包裝的對象,我們可以移除所需的裝飾器,例如如果我們要刪除的裝飾C:

factory.RemoveDecorator(decoratedObj, replaceDecorator) 

因此,裝飾物會包裹對象的第二個參數。取決於我們需要刪除的裝飾器,我們會多次調用方法removedecorator。如果我們只想調用它,我們可以在我們的工廠編寫一個方法來查找哪個對象將被刪除。