假设我有一个名为A
的类,我想使用装饰器设计模式。如果我错了,请纠正我,但为了工作,我们需要创建一个装饰器类,比如ADecorator
,它将包含对A
实例的引用,以及所有其他装饰器将扩展此功能以添加功能。
我不明白为什么我们必须创建一个装饰器类,而不是使用A
实例?
答案 0 :(得分:25)
装饰器模式用于动态地向对象添加功能(即,在运行时)。通常,在编写类时,对象的功能会得到修复。但重要的一点是,对象的功能是以对对象客户端透明的方式扩展的,因为它实现了与原始对象将责任委托给装饰对象相同的接口。
装饰器模式适用于对象可能具有许多可选功能的场景。如果没有装饰器模式,则必须为每个对象选项配置创建不同的类。一个非常有用的例子来自O'Reilly的 Head First Design Patterns 一书。它使用的咖啡店就像StarBucks一样。
所以你有基本咖啡的方法,如成本。
public double cost(){
return 3.45;
}
然后客户可以添加0.35的奶油,因此您现在使用成本方法创建CoffeeCream类:
public double cost(){
return 3.80;
}
然后顾客可能想要价格为0.5的Mocha,他们可能想要Mocha with Cream或Mocha without Cream。所以你创建了CoffeeMochaCream和CoffeeMocha类。然后客户想要双奶油,所以你创建了一个类CoffeeCreamCream ...等你最终得到的是类爆炸。请原谅使用的不好的例子。这有点晚了,我知道这是微不足道的,但确实表明了这一点。
相反,您可以使用抽象成本方法创建Item抽象类:
public abstract class Item{
public abstract double cost();
}
你可以创建一个扩展Item的具体Coffee类:
public class Coffee extends Item{
public double cost(){
return 3.45;
}
}
然后创建一个扩展相同接口并包含Item的CoffeeDecorator。
public abstract class CoffeeDecorator extends Item{
private Item item;
...
}
然后你可以为每个选项创建具体的装饰器:
public class Mocha extends CoffeeDecorator{
public double cost(){
return item.cost() + 0.5;
}
}
请注意装饰器如何只是它是一个物品而不关心它包装的物体类型?它使用item对象的cost()并简单地添加自己的成本。
public class Cream extends CoffeeDecorator{
public double cost(){
return item.cost() + 0.35;
}
}
现在可以使用这几个类进行大量配置: e.g。
Item drink = new Cream(new Mocha(new Coffee))); //Mocha with cream
或
Item drink = new Cream(new Mocha(new Cream(new Coffee))));//Mocha with double cream
等等。
答案 1 :(得分:5)
我无法解释它比wikipedia文章更好。
答案 2 :(得分:3)
答案 3 :(得分:2)
在某些语言(如Ruby或JavaScript)中,您只需向A实例添加新功能即可。我注意到你的问题被标记为Java,所以我假设你在问为什么你不能用Java做这个。原因是Java是静态类型的。 A实例只能拥有类A定义或继承的方法。因此,如果您希望在运行时为A实例提供A未定义的方法,则必须在不同的类中定义此新方法。