Skip to content

装饰器

这在订单中使用。如果你一下子去看订单里的装饰器,可能会很懵。没关系,接下来我们将通过一个示例来讲解如何在项目里运用装饰器。

定义

顾名思义,装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

什么时候使用它

在不想增加很多子类的情况下扩展类。一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。这时候就应该考虑使用它。

优缺点

优点:

  • 装饰类和被装饰类可以独立发展,不会相互耦合。
  • 通过不同的装饰类排列组合,开发可以创造出更多不同行为的组合。

缺点:

  • 多层装饰比较复杂。

核心实现

  • 抽象构件(Component)

定义了原始对象和装饰器对象的公共接口或抽象类,可以是具体构件类的父类或接口。

  • 具体构件(ConcreteComponent)

被装饰的原始对象,它定义了需要添加新功能的对象。

  • 抽象装饰器(Decorator)

继承自抽象构件,它包含了一个抽象构件对象,并定义了与抽象构件相同的接口,同时可以通过组合方式持有其他装饰器对象。

  • 具体装饰器(ConcreteDecorator)

实现了抽象装饰器的接口,负责向抽象构件添加新的功能。具体装饰器通常会在调用原始对象的方法之前或之后执行自己的操作。

这是完整类图

decorators_1.png

示例

需求是,多种促销活动计算活动最终价格。

先来定义一个抽象组件:

java
/**
 * 计算金额接口类
 *
 */
public interface IBaseCount {
    
    void countAmount(CalculateOrderContext context);
}

再来定义具体构件:

java
/**
 * 计算金额基本类
 *
 */
public class BaseCount implements IBaseCount {

    @Override
    public void countAmount(CalculateOrderContext context) {
    }
}

再来定义抽象装饰器:

java
/**
 * 计算金额的抽象类
 *
 */
public abstract class BaseCountDecorator implements IBaseCount {

    private final IBaseCount count;

    public BaseCountDecorator(IBaseCount count) {
        this.count = count;
    }

    @Override
    public void countAmount(CalculateOrderContext context) {
        this.count.countAmount(context);
    }
}

接下来就是具体装饰器了:

java
/**
 * 限时抢购活动
 */
public class FlashSaleActivityDecorator extends BaseCountDecorator {
    public FlashSaleActivityDecorator(IBaseCount count) {
        super(count);
    }

    @Override
    public void countAmount(CalculateOrderContext context) {
        super.countAmount(context);
        System.out.println("限时抢购");
    }
}
java
/**
 * 满减活动
 */
public class FullReductionActivityDecorator extends BaseCountDecorator {
    public FullReductionActivityDecorator(IBaseCount count) {
        super(count);
    }

    @Override
    public void countAmount(CalculateOrderContext context) {
        super.countAmount(context);
        System.out.println("满减活动");
    }
}

接下来就是客户端调用了:

java
public static void main(String[] args) {
    IBaseCount baseCount = new BaseCount();
    baseCount = new FlashSaleActivityDecorator(baseCount);
    baseCount = new FullReductionActivityDecorator(baseCount);
    baseCount.countAmount(null);
}

通过这个简单的示例,演示了如何定义一个装饰器。