在某些情况下,我们需要再不修改现有对象结构的情况爱,动态的添加或删除,继承在这种情况下可能会导致类爆炸问题,而且修改现有的类可能会影响其他部分的代码。
装饰模式提供了一种在运行时动态的为对象添加新功能的方法,通过创建一个装饰类来包装原始类,装饰类具有与原始类相同的接口,它内部包含一个指向原始对象的引用,并且可以根据需要包装额外的功能。这样通过组合不同的装饰类来构建出具有不同功能组合的对象。
装饰模式的优点包括避免了类爆炸问题,因为你可以已通过组合少量的装饰类累实现各种功能组合。它使得功能的增加和修改更加灵活,而不会影响到其他部分的代码,然而,装饰模式可能会导致增加很多小型的类,从而增加了代码的复杂性。
在装饰器模式中,通常涉及以下角色:
- 组件(Component):定义了一个抽象接口,可以是具体对象或者装饰器所共有的接口。
- 具体组件(Concrete Component):实现了组件接口,是被装饰的原始对象。
- 装饰器(Decorator):持有一个指向组件对象的引用,并实现了组件的接口,它可以包含额外的功能,也可以将请求传递给组件对象。
- 具体装饰器(Concrete Decorator):扩展了装饰器类,通过添加额外的功能来装饰具体组件。
通过这种方式,装饰模式允许你将功能嵌套的堆叠在一起,以实现各种不同的功能组合,同时保持代码的灵活性和可维护性。
代码实例:
// 首先定义一个咖啡接口
interface Coffee {
double cost();
String description();
}
// 实现基本的咖啡类
class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 2.0;
}
@Override
public String description() {
return "Simple Coffee";
}
}
// 创建装饰器抽象类
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
@Override
public double cost() {
return decoratedCoffee.cost();
}
@Override
public String description() {
return decoratedCoffee.description();
}
}
// 实现具体的装饰器类
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return super.cost() + 1.0;
}
@Override
public String description() {
return super.description() + ", with Milk";
}
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return super.cost() + 0.5;
}
@Override
public String description() {
return super.description() + ", with Sugar";
}
}
// 在这个示例中,Coffee 接口定义了基本的咖啡功能。SimpleCoffee 类实现了基本的咖啡。
// CoffeeDecorator 是装饰器的抽象类,它维护一个被装饰的咖啡对象。
// MilkDecorator 和 SugarDecorator 分别实现了具体的装饰器,通过在原始咖啡上添加新的功能。
public class DecoratorPatternExample {
public static void main(String[] args) {
Coffee simpleCoffee = new SimpleCoffee();
System.out.println("Cost: $" + simpleCoffee.cost() + ", Description: " + simpleCoffee.description());
Coffee milkCoffee = new MilkDecorator(simpleCoffee);
System.out.println("Cost: $" + milkCoffee.cost() + ", Description: " + milkCoffee.description());
Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
System.out.println("Cost: $" + sugarMilkCoffee.cost() + ", Description: " + sugarMilkCoffee.description());
}
}