Java设计模式——装饰者模式
1.简介
'装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许用户通过在一个对象上动态地添加职责或行为来增强其功能。这种类型的设计模式属于对象结构型模式,在不需要改变一个对象的内部结构的条件下,给对象动态地增加一些额外的职责。装饰者模式相比生成子类更为灵活。
2.核心组成
装饰者模式主要包含以下四种角色:
- 抽象组件(Component):定义一个对象的接口,可以给这些对象动态地添加职责。
- 具体组件(ConcreteComponent):实现或继承抽象组件,并添加基础的行为或属性。
- 装饰者(Decorator):持有一个抽象组件的引用,并定义一个与抽象组件一致的接口。
- 具体装饰者(ConcreteDecorator):实现装饰者接口,并给具体组件对象添加额外的职责。
3.工作原理
装饰者模式的工作原理是动态地将责任附加到对象上。若要扩展一个类的功能,装饰者提供了一个比继承更有弹性的替代方案。
4.使用场景
- 动态地给一个对象添加功能:装饰者模式允许我们在运行时动态地给一个对象添加职责,而不是在编译时静态地定义。
- 扩展功能不改变接口:使用装饰者模式时,不需要修改现有类的接口,就可以在运行时动态地扩展类的功能。
- 透明地使用对象:装饰者模式中的装饰者对象和被装饰对象实现了相同的接口,所以客户端代码可以透明地使用它们,不需要知道它们到底是装饰者对象还是被装饰对象。
5.优缺点
优点:
- 装饰者和被装饰对象有相同的超类,因此继承了装饰者模式中的装饰对象和被装饰对象的类型一致性的特点。
- 装饰者模式可以动态地扩展一个实现类的功能,且可以无限制地使用装饰模式。
- 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点:
- 多层装饰比较复杂。
- 装饰模式会导致设计中出现许多小类,如果过度使用会使程序变得很复杂。
6.Java的实现例子
我们将以Beverage
(饮料)作为抽象组件,并有一个具体的Coffee
(咖啡)实现。我们将为咖啡添加一些装饰者,如Milk
(牛奶)和Sugar
(糖)。
首先,定义Beverage
接口和Coffee
类:
// 抽象组件:Beverage
public interface Beverage {
String getDescription();
double cost();
}
// 具体组件:Coffee
public class Coffee implements Beverage {
@Override
public String getDescription() {
return "Coffee";
}
@Override
public double cost() {
return 2.0;
}
}
接下来,定义Decorator
类,它实现了Beverage
接口并持有一个Beverage
对象的引用:
// 装饰者:Decorator
public abstract class Decorator implements Beverage {
protected Beverage beverage;
public Decorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription();
}
@Override
public double cost() {
return beverage.cost();
}
}
现在,定义具体的装饰者类,如Milk
和Sugar
:
// 具体装饰者:Milk
public class Milk extends Decorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
@Override
public double cost() {
return beverage.cost() + 0.5;
}
}
// 具体装饰者:Sugar
public class Sugar extends Decorator {
public Sugar(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Sugar";
}
@Override
public double cost() {
return beverage.cost() + 0.3;
}
}
最后,在主程序中使用装饰者:
public class BeverageTest {
public static void main(String[] args) {
Beverage beverage = new Coffee();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
Beverage beverageWithMilk = new Milk(beverage);
System.out.println(beverageWithMilk.getDescription() + " $" + beverageWithMilk.cost());
Beverage beverageWithMilkAndSugar = new Sugar(beverageWithMilk);
System.out.println(beverageWithMilkAndSugar.getDescription() + " $" + beverageWithMilkAndSugar.cost());
}
}