问题
在某些情况下,我们需要在不修改现有对象结构的情况下,动态地添加功能或责任。继承在这种情况下可能会导致类爆炸问题,而且修改现有类可能会影响到其他部分的代码。
解决方案
装饰模式提供了一种在运行时动态地为对象添加新功能的方法,通过创建一个装饰类来包装原始类。装饰类具有与原始类相同的接口,它内部包含一个指向原始对象的引用,并且可以根据需要包装额外的功能。这样,你可以通过组合不同的装饰类来构建出具有不同功能组合的对象。
效果
装饰模式的优点包括避免了类爆炸问题,因为你可以通过组合少量的装饰类来实现各种功能组合。它也使得功能的增加和修改更加灵活,不会影响到其他部分的代码。然而,装饰模式可能会导致增加很多小型的类,从而增加了代码的复杂性。
在装饰模式中,通常涉及以下角色:
- 组件(Component):定义了一个抽象的接口,可以是具体对象或装饰器所共有的接口。
- 具体组件(Concrete Component):实现了组件接口,是被装饰的原始对象。
- 装饰器(Decorator):持有一个指向组件对象的引用,并实现了组件的接口。它可以包含额外的功能,也可以将请求传递给组件对象。
- 具体装饰器(Concrete Decorator):扩展了装饰器类,通过添加额外的功能来装饰具体组件。
通过这种方式,装饰模式允许你将功能嵌套地堆叠在一起,以实现各种不同的功能组合,同时保持代码的灵活性和可维护性。
动态的给一个对象添加一些额外的功能。就扩展功能而言,装饰者模式比生成子类方式更为灵活。
装饰器模式是一种结构性设计模式,它允许您在不影响同一类的其他对象的行为的情况下,静态或动态地向单个对象添加行为。 当您想要在运行时添加或删除对象的功能时,或者当您想要减少创建不同行为组合所需的子类数量时,此模式非常有用。
在Java中,使用继承和组合的结合来实现装饰器模式。 具体来说,您需要创建一个基类或接口来定义对象的核心行为,然后创建一个或多个装饰器类来向对象添加附加行为。 每个装饰器类都具有对其装饰的对象的引用,并且它可以在委托给对象的原始行为之前或之后修改对象的行为。
装饰器模式适用于以下场景:
- 在不修改现有代码的情况下,向现有类添加新的功能。
- 在运行时动态地向对象添加新的行为。
- 以不同的方式组合对象,以实现不同的行为。
使用装饰器模式时需要注意以下几点:
- 装饰器类需要实现与被装饰对象相同的接口,以便可以对被装饰对象进行包装。
- 装饰器类应该在调用被装饰对象的方法之前或之后添加新的行为。
- 不要创建过多的装饰器对象,否则会导致代码变得复杂难以维护。

java
public interface Pizza {
public String getDescription();
public double getCost();
}
// 具体组件
public class PlainPizza implements Pizza {
public String getDescription() {
return "薄饼";
}
public double getCost() {
return 4.00;
}
}
// 装饰器
public abstract class ToppingDecorator implements Pizza {
protected Pizza pizza;
public ToppingDecorator(Pizza pizza) {
this.pizza = pizza;
}
public String getDescription() {
return pizza.getDescription();
}
public double getCost() {
return pizza.getCost();
}
}
// 具体装饰器
public class Cheese extends ToppingDecorator {
public Cheese(Pizza pizza) {
super(pizza);
}
public String getDescription() {
return pizza.getDescription() + ",马苏里拉奶酪";
}
public double getCost() {
return pizza.getCost() + 0.50;
}
}
// 具体装饰器
public class Pepperoni extends ToppingDecorator {
public Pepperoni(Pizza pizza) {
super(pizza);
}
public String getDescription() {
return pizza.getDescription() + ",意大利辣香肠";
}
public double getCost() {
return pizza.getCost() + 1.00;
}
}
// 客户端代码
public class PizzaShop {
public static void main(String[] args) {
Pizza pizza = new PlainPizza();
pizza = new Cheese(pizza);
pizza = new Pepperoni(pizza);
System.out.println(pizza.getDescription());
System.out.println("成本:$" + pizza.getCost());
}
}
实际应用场景
比如为商品添加不同的属性或功能,如包装、赠品等。
java
interface ProductComponent {
double getPrice();
}
class BasicProduct implements ProductComponent {
@Override
public double getPrice() {
return 50.0;
}
}
class GiftDecorator extends ProductComponent {
private ProductComponent component;
public GiftDecorator(ProductComponent component) {
this.component = component;
}
@Override
public double getPrice() {
return component.getPrice() + 10.0;
}
}