设计模式之装饰器模式

结构型—-装饰器模式也叫包装模式,是指再不改变原有对象的基础上将新功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原对象功能)

优点:

  • 完全符合开闭原则
  • 装饰功能即插即用
  • 多种装饰排列组合,能获得多种效果

缺点:

  • 会增加更多的代码文件
  • 动态装饰、多层次装饰模型会很复杂

源码案例:

1、 jdk的BIO源码中,InputStream OutputStream Reader Writer接口的实现,就是使用了装饰器模式,针对不同类型的资源的输入输出,可以根据业务场景添加功能

2、 Mybatis源码中,二级缓存的实现就是用的装饰器迷失,对基本执行器BaseExecutor 进行装饰,执行器就拥有了缓存功能:

1
new CacheExecutor(new BaseExecutor());

应用关键点:

  • 首先要有一个接口
  • 然后要有一个实现类的基本款
  • 装饰类亦实现接口,并持有一个此接口实现类对象,首次装饰构造时传入基本款,可以嵌套装饰
  • 装饰类实现接口方法可以调用基本款,并对其加强(装饰)

案例:代码中日志接口用的很熟悉了,有一天有一个需求,写日志时要将string类型的日志换成json格式

装饰器模式实现:

  • 首先要一个接口:现成的Logger接口

  • 然后需要一个基本款:

1
LoggerFactory.getLogger(clazz);
  • 装饰器类:
1
2
3
4
5
6
7
8
public class LoggerDecorator implements Logger {    
protected Logger logger ;
public LoggerDecorator(Logger logger){
this.logger = logger;
}
//以下为接口方法
...
}

子装饰类

1
2
3
4
5
6
7
8
9
10
11
public class JsonLogger extends LoggerDecorator {   
public JsonLogger(Logger logger) {
super(logger);
}
@Override
public void info(String s) {
JSONObject res = new JSONObject();
res.put("message",s);
logger.info(res.toJSONString());
}
}
1
2
3
4
5
public class JsonLoggerFactory {  
public static Logger getLogger(Class clazz){
return new JsonLogger(LoggerFactory.getLogger(clazz));
}
}
1
2
3
4
5
6
7
8
public class Test {   
private static final Logger LOGGER_1 = LoggerFactory.getLogger(Test.class);
private static final Logger LOGGER = JsonLoggerFactory.getLogger(Test.class);
public static void main(String[] args){
LOGGER_1.info("测试错误");
LOGGER.info("测试错误");
}
}

输出:

1
2
16:07:47.704 [main] INFO com.panda.decorator.jsonlogger.Test - 测试错误
16:07:47.794 [main] INFO com.panda.decorator.jsonlogger.Test - {"message":"测试错误"}