装饰模式

1 定义

装饰模式也成为包装模式,此设计模式属于结构型模式。
定义:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

模式结构

角色介绍

  • Component:抽象组件
    可以是一个接口或者抽象类,定义我们最核心的对象,也就是被装饰的原始对象。
  • ConcreteComponent:组件的具体实现
    Component类的基本实现,也就是要装饰的具体对象。
  • Decorator:抽象装饰者
    作用是为了装饰我们的组件对象,其内部必有一个指向Component对象的引用。
  • ConcreteDecoratorA:抽象装饰者的具体实现。
  • ConcreteDecoratorB:抽象装饰者的具体实现。

通用模式代码

  • 抽象组件,被装饰的原始对象
public abstract class Component {

    /**
     * 抽象的方法,可以有多个
     */
    public abstract void operate();
}
  • 组件的具体实现,即被装饰的具体对象
public class ConcreteComponent extends Component{

    @Override
    public void operate() {
        // 在这里写你的逻辑
    }
}
  • 抽象装饰者,其内部一定要有一个指向组件对象的引用。
public class Decorator extends Component{

    private Component mComponent; // 持有一个Component对象的引用
    
    /**
     * 构造方法
     * @param component
     */
    public Decorator(Component component){
        this.mComponent=component;
    }

    @Override
    public void operate() {
        mComponent.operate();
    }
}
  • 抽象装饰者的具体实现
public class ConcreteDecoratorA extends Decorator{

    /**
     * 构造方法
     *
     * @param component
     */
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operate() {
         // 装饰方法A和B的调用顺序可变
        operateA();
        super.operate();
        operateB();
    }

    /**
     * 自定义的装饰方法
     */
    public void operateA(){
        // 装饰逻辑
    }

    /**
     * 自定义的装饰方法
     */
    public void operateB(){
        // 装饰逻辑
    }

}
public class ConcreteDecoratorB extends Decorator{

    /**
     * 构造方法
     *
     * @param component
     */
    public ConcreteDecoratorB(Component component) {
        super(component);
    }


    @Override
    public void operate() {
         // 装饰方法A和B的调用顺序可变
        operateA();
        super.operate();
        operateB();
    }

    /**
     * 自定义的装饰方法
     */
    public void operateA(){
        // 装饰逻辑
    }

    /**
     * 自定义的装饰方法
     */
    public void operateB(){
        // 装饰逻辑
    }
    
}
  • 测试代码
 // 构造被装饰的对象
        Component component=new ConcreteComponent();
        // 根据组件对象构造装饰者对象A并调用,此时相当于给组件对象添加装饰者A的功能方法
        Decorator decoratorA=new ConcreteDecoratorA(component);
        decoratorA.operate();
        // 根据组件对象构造装饰者对象B并调用,此时相当于给组件对象添加装饰者B的功能方法
        Decorator decoratorB=new ConcreteDecoratorB(component);
        decoratorB.operate();

三 实例

我们再以制作奶茶为例,在桥接模式里,我们实现了奶茶两个维度的变化,大小杯和加不加糖。在装饰模式下,我们要实现装饰一杯奶茶,动态地给奶茶添加一些功能。比如加冰,加蓝莓,加珍珠,计算价格等。

  • 抽象组件,被装饰的原始对象,在我们的实例是指制作一杯饮料
/*
 * 抽象组件,被装饰的原始对象
 * @author Jackson
 * @version 1.0.0
 * since 2019 03 13
 */
public abstract class Beverage {

    /**
     * 抽象方法,制作饮料
     */
    public abstract void makeBeverage();

}
  • 组件的具体实现,被装饰的具体对象,在我们的实例,制作一杯奶茶
/*
 * 组件的具体实现,被装饰的具体对象
 * @author Jackson
 * @version 1.0.0
 * since 2019 03 13
 */
public class MilkTea extends Beverage {

    @Override
    public void makeBeverage() {
        // 奶茶的基本逻辑
        System.out.println("     添加奶茶    ");
    }
}
  • 抽象的装饰者,其内部保持一个被装饰类的引用
/*
 * 抽象的装饰者
 * @author Jackson
 * @version 1.0.0
 * since 2019 03 13
 */
public abstract class Decorator extends Beverage {

    protected Beverage mBeverage; // 其内部保持一个被装饰类的引用

    /**
     * 构造方法
     * @param beverage
     */
    public Decorator(Beverage beverage){
        this.mBeverage=beverage;
    }

    @Override
    public void makeBeverage() {
        // 调用Beverage的makeBeverage()方法)
        mBeverage.makeBeverage();
    }
}
  • 具体装饰者,加蓝莓,加冰,加蓝莓的奶茶
/*
 * 具体装饰者,加蓝莓
 * @author Jackson
 * @version 1.0.0
 * since 2019 03 13
 */
public class BlueberryDecorator extends Decorator{
    /**
     * 构造方法
     *
     * @param beverage
     */
    public BlueberryDecorator(Beverage beverage) {
        super(beverage);
    }


    @Override
    public void makeBeverage() {
        // 顺序:加冰--加饮料--加蓝莓--收钱,顺序按照需求可变
        addIce();
        super.makeBeverage();
        addBlueberry();
        price();

    }

    /**
     * 添加冰块
     */
    private void addIce(){
        System.out.println("    添加冰块   ");
    }

    /**
     * 添加蓝莓
     */
    private void addBlueberry(){
        System.out.println("     添加蓝莓    ");
    }

    /**
     * 计算价格
     */
    private void price(){
        System.out.println("     蓝莓奶茶的价格是5元    ");
    }

}
    • 具体装饰者,加珍珠的奶茶
/*
 * 具体装饰者,珍珠奶茶
 * @author Jackson
 * @version 1.0.0
 * since 2019 03 13
 */
public class PearlDecorator extends Decorator{
    /**
     * 构造方法
     *
     * @param beverage
     */
    public PearlDecorator(Beverage beverage) {
        super(beverage);
    }


    @Override
    public void makeBeverage() {
        // 顺序:收钱--加珍珠丸子--加饮料,顺序按照需求可变
        price();
        addPearl();
        super.makeBeverage();
    }

    /**
     * 添加珍珠丸子
     */
    private void addPearl(){
        System.out.println("   添加珍珠丸子   ");
    }

    /**
     * 计算价格
     */
    private void price(){
        System.out.println("   珍珠奶茶的价格是6元   ");
    }
}
  • 测试代码
 // 首先要现有一杯奶茶
 MilkTea milkTea=new MilkTea();
 System.out.println("------制作蓝莓奶茶-------");
 // 制作蓝莓奶茶
  BlueberryDecorator blueberryDecorator=new BlueberryDecorator(milkTea);
  blueberryDecorator.makeBeverage();
  // 制作珍珠奶茶
  System.out.println("------制作珍珠奶茶-------");
  PearlDecorator pearlDecorator=new PearlDecorator(milkTea);
  pearlDecorator.makeBeverage();
运行结果

四 优点

  • 比继承更灵活
    装饰模式比继承更加灵活,继承是静态的,而且一旦继承,所有子类都有一样的功能,而装饰模式把功能分离到每个装饰器中,然后通过组合的方式,组合的方式决定装饰后对象的最终功能。
  • 更容易复用功能
    装饰模式把一系列复杂的功能分散到每个装饰器中,一般一个装饰器只实现一个功能,从而可以更好地复用装饰器。

五 使用场景

  • 需要扩展一个类的功能,或者给一个类增加附加功能时可以考虑使用装饰者模式。

你可能感兴趣的:(装饰模式)