(结构型模式)装饰器模式

115 阅读2分钟

简介

装饰器模式就是再不改原有类的基础上给类新增功能。不改变原有类,类似于继承、AOP切面的模式。可以避免继承导致的子类过多,也可以避免AOP带来的复杂性。

角色

  • 抽象组件(Component):装饰器模式中最核心的对象,即原始对象,一般是一个接口或者是抽象类

  • 具体组件(Concrete Component):抽象组件的实现类,装饰器模式装饰的目标就是它

  • 装饰角色(Decorator):组合了抽象组件,同时定义一个抽象方法用来扩展抽象组件提供的能力,一般是一个抽象类

  • 具体装饰角色(Concrete Decorator):实现装饰角色提供的抽象方法,是抽象组件提供能力的具体扩展实现

使用场景

  1. 需要动态的对对象的功能进行扩展;
  2. 不能或者不便以子类的方式扩展功能,可以代替继承;
  3. 可以用来限制对象的执行条件,也可以进行参数控制和检查等;

具体案例

饼子抽象类

public interface Cake {


    public abstract String getCakeMsg();

    public abstract BigDecimal getPrice();

}

具体饼子类

public class BaseCake implements Cake {
    @Override
    public String getCakeMsg() {
        return "鸡蛋灌饼";
    }

    @Override
    public BigDecimal getPrice() {
        return new BigDecimal(5);
    }
}

饼子装饰器抽象类

public abstract class CakeDecorator implements Cake {

    private Cake cake;

    public CakeDecorator(Cake cake){
        this.cake = cake;
    }

    @Override
    public String getCakeMsg() {
        return this.cake.getCakeMsg();
    }

    @Override
    public BigDecimal getPrice() {
        return this.cake.getPrice();
    }

}

火腿装饰器

public class CakeAddHamDecorator extends CakeDecorator {

    public CakeAddHamDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + " + 火腿";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal(2));
    }
}

里脊装饰器

public class CakeAddTenderloinDecorator extends CakeDecorator {

    public CakeAddTenderloinDecorator(Cake cake) {
        super(cake);
    }

    @Override
    public String getCakeMsg() {
        return super.getCakeMsg() + " + 里脊";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal(3));
    }
}

测试

public class Demo {

    public static void main(String[] args) {
        Cake baseCake = new BaseCake();
        System.out.println(baseCake.getCakeMsg() + ",价格:" + baseCake.getPrice());
        //加火腿
        baseCake = new CakeAddHamDecorator(baseCake);
        System.out.println(baseCake.getCakeMsg() + ",价格:" + baseCake.getPrice());
        //加里脊
        baseCake = new CakeAddTenderloinDecorator(baseCake);
        System.out.println(baseCake.getCakeMsg() + ",价格:" + baseCake.getPrice());
    }
}

结果

20220907-185200.jpg

装饰器模式优缺点

优点

  • 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用
  • 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
  • 装饰器完全遵守开闭原则

缺点

  • 从代码层面来看,使用装饰器模式会出现更多的代码,更多的类,增加程序复杂性
  • 动态装饰时,多层装饰时会更复杂