简介
装饰器模式就是再不改原有类的基础上给类新增功能。不改变原有类,类似于继承、AOP切面的模式。可以避免继承导致的子类过多,也可以避免AOP带来的复杂性。
角色
-
抽象组件(Component):装饰器模式中最核心的对象,即原始对象,一般是一个接口或者是抽象类
-
具体组件(Concrete Component):抽象组件的实现类,装饰器模式装饰的目标就是它
-
装饰角色(Decorator):组合了抽象组件,同时定义一个抽象方法用来扩展抽象组件提供的能力,一般是一个抽象类
-
具体装饰角色(Concrete Decorator):实现装饰角色提供的抽象方法,是抽象组件提供能力的具体扩展实现
使用场景
- 需要动态的对对象的功能进行扩展;
- 不能或者不便以子类的方式扩展功能,可以代替继承;
- 可以用来限制对象的执行条件,也可以进行参数控制和检查等;
具体案例
饼子抽象类
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());
}
}
结果
装饰器模式优缺点
优点
- 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用
- 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
- 装饰器完全遵守开闭原则
缺点
- 从代码层面来看,使用装饰器模式会出现更多的代码,更多的类,增加程序复杂性
- 动态装饰时,多层装饰时会更复杂