Java 为什么在装饰者模式中使用抽象装饰者;有一个;及;是一个;抽象组件?
我在许多与decorator模式相关的UML类图中看到,抽象decorator既包含抽象组件,又扩展了抽象类组件 例如,在第二个示例中,与以下链接中的咖啡制作场景相关: 类Java 为什么在装饰者模式中使用抽象装饰者;有一个;及;是一个;抽象组件?,java,decorator,Java,Decorator,我在许多与decorator模式相关的UML类图中看到,抽象decorator既包含抽象组件,又扩展了抽象类组件 例如,在第二个示例中,与以下链接中的咖啡制作场景相关: 类CoffeeDecorator扩展了抽象组件Coffee,并包含类型为Coffee的字段。为什么呢?这仅仅是一种情况,还是我们应该总是构建这样的“装饰系统”,为什么 我认为应该只需要CoffeeDecorator包含它想要修饰的组件,因为CoffeeDecorator实际上不是Coffee可以在任何可以使用包装对象的地方使用
CoffeeDecorator
扩展了抽象组件Coffee
,并包含类型为Coffee
的字段。为什么呢?这仅仅是一种情况,还是我们应该总是构建这样的“装饰系统”,为什么
我认为应该只需要
CoffeeDecorator
包含它想要修饰的组件,因为CoffeeDecorator
实际上不是Coffee
可以在任何可以使用包装对象的地方使用修饰器/包装器(“是一个”)。这就是为什么它必须扩展/实现类/接口
decorator/wrapper还有一个对它想要修饰/包装的实例的引用(“has”)
如问题中的链接示例所示,您可以编写:
Coffee coffee = new WithMilk(new SimpleCoffee());
其中,
WithMilk
是一个装饰器。装饰器和装饰类实现相同的接口。这允许装饰类向装饰类的每个方法(在接口中声明)添加额外的功能。这就是包装/装饰的意思
public class SimpleCoffee extends Coffee {
@Override
public double getCost() {
return 1;
}
@Override
public String getIngredients() {
return "Coffee";
}
}
public abstract class CoffeeDecorator extends Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee c) {
this.decoratedCoffee = c;
}
public double getCost() { // Implementing methods of the abstract class
//you can add extra functionality here.
return decoratedCoffee.getCost();
}
public String getIngredients() {
//you can add extra functionality here.
return decoratedCoffee.getIngredients();
}
}
public class BiggerDecorator extends Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee c) {
this.decoratedCoffee = c;
}
public double getCost() { // Implementing methods of the abstract class
return decoratedCoffee.getCost();
}
public String getIngredients() {
return decoratedCoffee.getIngredients();
}
}
Decorator类可以由较大的Decorator进行装饰
public class BiggerDecorator extends Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee c) {
this.decoratedCoffee = c;
}
public double getCost() { // Implementing methods of the abstract class
return decoratedCoffee.getCost();
}
public String getIngredients() {
return decoratedCoffee.getIngredients();
}
}
您现在可以执行以下操作。类在此结构中
Coffee coffeeDecorator=new CoffeeDecorator(new Coffee);
Coffee biggerDecorator=new BiggerDecorator(coffeeDecorator);
为了多态性,decorator类必须实现该接口。您的问题对我来说似乎有点循环……实现一个接口并使该接口的实例“装饰”是decorator模式的定义 所以你的问题有点像问“为什么装饰者模式使用装饰者模式?” 如果你正在包装的东西和你自己之间没有一个共同的接口,它只是一个has-a关系,或者,如果你正在将你正在包装的东西的接口调整到其他接口,它可能是适配器模式 我认为您真正的问题是“为什么decorator模式有用?是什么使得实现与您包装的东西相同的接口有用?” 装饰器模式允许对相同的行为进行变化 当您有一个系统必须处理一些细微不同的事情,但又不想知道复杂性,并且能够以相同的方式处理它们时,decorator模式的最大价值就来了。当然,这通常是我们从接口得到的。但在某些情况下,相同接口的多个实现并不是最佳解决方案……在经典示例中,假设您尝试为星巴克提供的每种类型的咖啡编写一个单独的类 您将从基础开始,但逐渐发现自己需要编写类,如
VentimoChachaiWhipWith肉桂onTop
。每次添加新的风味成分时,您都需要编写几十个新类,而每次删除一个新类时,就会有几十个类过时
另一方面,通过decorator模式,您可以为每种饮料创建一个单独的类,并使软件系统的大部分不必处理各种饮料类型;他们可以通过饮料
界面对每种饮料进行相同的处理(无论它有多少附加组件)
当结账的人点击Chai按钮时,您只需制作一个new Chai()
,由于其他属性可以添加到任意饮料中,您只需将其包装成new Venti(饮料)
,new Mocha(饮料)
,new Whip(饮料)
,new with肉桂(饮料)
,等。当客户要求加载项时,登记处的人员点击按钮
装饰图案的限制
这种模式有它的局限性,因为与每种调味品都使用一组布尔值相比,你更难反省自己到底喝了什么。我敢肯定,在为星巴克设计收银机时,它对跟踪饮料类型并没有什么实际用处,因为它不太擅长处理“哦,我指的是黑莓口味,不是覆盆子”…在decorator模式中支持这一点需要通过几个嵌套的饮料decorator进行内省,以找到需要删除的Rasberry
decorator
它也不擅长处理复杂的相互关系……如果搅打头需要知道它与什么基本饮料类型相关,就需要知道它是否应该在价格上增加0.25美元,那么decorator模式就不是很有用了:decorator模式适用于各种装饰不需要知道它们包装的是什么具体实现的情况。当我们可以使用它时,它有助于减少耦合
我真正觉得有用的东西
我认为我们使用这个例子来解释decorator模式,主要是因为我们很容易谈论需要创建的类的数量的潜在指数节约,而许多实际的例子表明装饰有用,但实际上并没有使用decorator模式的属性
我能想到的案例是,在我们公司中使用了一些类似于该模式的东西,我们希望在流程中添加一些日志记录。例如,通过装饰EclipseIProgressMonitor,我们可以在每次显示的任务或子任务名称更改时检测,并记录流程的每个步骤花费的时间,以便知道哪些步骤花费的时间最多
作为一个装饰者,我们可以访问所有日志信息