2010-01-30 65 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。如果我们只想调用它,我们可以在我们的工厂编写一个方法来查找哪个对象将被删除。