定义:
结构型装饰器模式(Decorator Pattern || Wrapper Pattern )指在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的替代方案,生活中常见的例子:类似煎饼,水果蛋糕...
适用场景:
1.用于扩展一个类的功能或给一个类附加职责。
2.动态的给一个对象添加功能,这些功能可以再动态的撤销。
优点:
1.装饰器属于继承的有力补充,比继承灵活,不改变原有对象的情况下动态的给对象扩展功能,增加即用。
2.通过使用不同装饰器类以及这些类的排序组合,可实现不同效果。
3.完全遵守开闭原则。
缺点:
1.会出现更多的代码与类,增加了程序复杂度
2.动态装饰时会更复杂
示例:
/**
* 抽象组件,以煎饼为例
*/
public abstract class Battercake {
protected abstract String getMsg();
protected abstract BigDecimal getPrice();
}
/**
* 一个正常的煎饼,不加任何辅材
*/
public class BaseBattercake extends Battercake {
public String getMsg(){ return "煎饼"; }
public BigDecimal getPrice(){
return new BigDecimal(5);
}
}
/**
* 装饰器,继承煎饼抽象
*/
public class BattercakeDecorator extends Battercake{
private Battercake battercake;
/**
* 装饰器最大特征:
* 构造方法必须,也就是说子类必须实现一个带参数的构造方法
* 并且参数一定是抽象组件
*/
BattercakeDecorator(Battercake battercake){
this.battercake = battercake;
}
protected String getMsg(){
return this.battercake.getMsg();
}
protected BigDecimal getPrice(){
return this.battercake.getPrice();
}
}
/**
* 需要在煎饼上加鸡蛋,衍生出第二个装饰器
*/
public class EggDecorator extends BattercakeDecorator{
/**
* 构造器调用父类
*/
EggDecorator(Battercake battercake){
super(battercake);
}
protected String getMsg(){
// 增加辅材
return super.getMsg() + ",一个鸡蛋";
}
protected BigDecimal getPrice(){
return super.getPrice().add(new BigDecimal(1));
}
}
/**
* 需要在煎饼上加香肠,衍生出第三个装饰器,以此类推。
*/
public class SauageDecorator extends BattercakeDecorator{
/**
* 构造器调用父类
*/
SauageDecorator(Battercake battercake){
super(battercake);
}
protected String getMsg(){
// 增加辅材
return super.getMsg() + ",一根香肠";
}
protected BigDecimal getPrice(){
return super.getPrice().add(new BigDecimal(2));
}
}
// 模拟客户端
public class MainExcute {
// 当前log输出是字符串,可将log封装成装饰器,输出json格式。
private final static Logger logger = Logger.getLogger(MainExcute.class);
public static void main(String[] args) {
/**
* 使用时可以透明动态的扩展,需要什么就创建不同的装饰器
*/
Battercake battercake = new BaseBattercake();
logger.info(battercake.getMsg()+":总价"+battercake.getPrice()+"元");
battercake = new EggDecorator(battercake);
battercake = new EggDecorator(battercake);
logger.info(battercake.getMsg()+":总价"+battercake.getPrice()+"元");
battercake = new SauageDecorator(battercake);
logger.info(battercake.getMsg()+":总价"+battercake.getPrice()+"元");
/**
* 装饰器在源码中的应用
* io流中也用的比较多,例:InputStream -> FileInputStream —> BufferedInputStream
*/
}
}
类图:
image.png