设计模式之装饰器模式详解
文章目录
- 设计模式之装饰器模式详解
- 一、什么是装饰器模式
- 二、装饰器模式的角色组成
- 三、装饰器模式通用写法示例
- 四、装饰器模式业务中的应用举例
- 五、装饰器模式优缺点
一、什么是装饰器模式
装饰器模式(Decorator Pattern) 也称为包装模式(Wrapper Pattern) 是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。装饰器模式的核心是功能扩展,使用装饰器模式可以透明且动态地扩展类的功能。
二、装饰器模式的角色组成
我们先来看下装饰器模式的通用类图:
- 抽象组件(Component): 可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为;
- 具体组件(
ConcreteComponent
): 实现/继承Component的一个具体对象,也即被装饰对象; - 抽象装饰器(Decorator): 通用的装饰
ConcreteComponent
的装饰器,其内部必然有一个属性指向Component抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个Component抽象组件,这是强制的通用行为(当然,如果系统中逻辑单一,并不需要实现许多装饰器,那么我们可以直接省略该类,而直接实现一个具体装饰器(ComcreteDecorator
)即可); - 具体装饰器(
ConcreteDecorator
): Decorator的具体实现类,理论上,每个ConcreteDecorator
都扩展了Component对象的一种功能;
三、装饰器模式通用写法示例
-
创建一个抽象组件Component来规定被装饰对象的行为
/*** 抽象组件** @author zdp* @date 2022/9/3 17:48*/ public abstract class Component {public abstract void execute(); }
-
创建具体组件
ConcreteComponent
/*** 具体组件(需要被装饰的组件)** @author zdp* @date 2022/9/3 17:48*/ public class ConcreteComponent extends Component {@Overridepublic void execute() {System.out.println("具体组件处理业务逻辑");}}
-
创建一个抽象装饰器Decorator
/*** 抽象装饰器(继承、实现抽象组件,并持有抽象组件)** @author zdp* @date 2022/9/3 17:49*/ public abstract class Decorator extends Component {/*** 抽象组件*/public Component component;public Decorator(Component component) {this.component = component;}/*** 将执行动作转发给组件本身执行,可以在转发前后做装饰** @author zdp* @date 2022/9/3 17:56*/public void execute() {component.execute();} }
-
创建具体装饰器
ConcreteDecorator
/*** 具体装饰器A继承抽象装饰器** @author zdp* @date 2022/9/3 17:49*/ public class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}/*** 具体组件动作执行前的装饰** @author zdp* @date 2022/9/3 17:58*/public void before(){System.out.println("ConcreteDecorator前置操作....");}/*** 具体组件动作执行后的装饰** @author zdp* @date 2022/9/3 17:58*/public void after(){System.out.println("ConcreteDecorator后置操作....");}/*** 组件本身执行的动作** @author zdp* @date 2022/9/3 18:01*/public void execute() {before();component.execute();after();} }
-
测试
/*** decorator 通用写法测试** @author zdp* @date 2022/9/3 17:50*/ public class Test {public static void main(String[] args) {//创建需要被装饰的组件Component component = new ConcreteComponent();//给对象透明的增加功能并调用Decorator decorator = new ConcreteDecorator(component);decorator.execute();} }
四、装饰器模式业务中的应用举例
需求:现系统中采用
slf4j
打印的日志为字符串格式,现使用装饰器模式将日志打印输出为Json
格式
现系统中的存在Logger接口以及Logger的实现,Logger就可视为抽象组件,Logger的具体实现就为具体组件,现我们只需完成抽象装饰器及具体的装饰器实现即可
-
创建抽象装饰器
DecoratorLogger
/*** 抽象装饰器,持有并实现抽象组件Logger** @author zdp* @date 2022/9/3 18:44*/ public abstract class DecoratorLogger implements Logger {protected Logger logger;public DecoratorLogger(Logger logger) {this.logger = logger;}@Overridepublic void info(String s) { }@Overridepublic void error(String s) { }// 其他实现方法省略.... }
-
创建具体装饰器
JsonLogger
/*** 具体装饰器: Json-logger** @author zdp* @date 2022/9/3 18:47*/ public class JsonLogger extends DecoratorLogger {public JsonLogger(Logger logger) {super(logger);}@Overridepublic void info(String message) {JSONObject obj = new JSONObject();obj.put("message", message);logger.info(obj.toString());}@Overridepublic void error(String message) {JSONObject obj = new JSONObject();obj.put("message", message);logger.error(obj.toString());}}
-
构造一个Factory
/*** JsonLoggerFactory** @author zdp* @date 2022/9/4 22:28*/ public class JsonLoggerFactory {public static JsonLogger getLogger(Class<?> clazz){return new JsonLogger(LoggerFactory.getLogger(clazz));}}
-
测试
/*** JsonLogger Test* * @author zdp* @date 2022/9/3 17:50*/ public class Test {private static final Logger logger = LoggerFactory.getLogger(Test.class);private static final Logger jsonLogger = JsonLoggerFactory.getLogger(Test.class);public static void main(String[] args) {logger.info(" logger info 日志打印....");jsonLogger.info(" jsonLogger info 日志打印....");System.out.println();logger.error("logger error日志打印....");jsonLogger.error("jsonLogger error日志打印....");} }
五、装饰器模式优缺点
- 优点
- 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用
- 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
- 装饰器完全遵守开闭原则
- 缺点
- 从代码层面来看,使用装饰器模式会出现更多的代码,更多的类,增加程序复杂性
- 动态装饰时,多层装饰时会更复杂