设计模式之装饰器模式详解
·
设计模式之装饰器模式详解
一、什么是装饰器模式
装饰器模式(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 { @Override public 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; } @Override public void info(String s) { } @Override public 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); } @Override public void info(String message) { JSONObject obj = new JSONObject(); obj.put("message", message); logger.info(obj.toString()); } @Override public 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日志打印...."); } }
五、装饰器模式优缺点
- 优点
- 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用
- 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
- 装饰器完全遵守开闭原则
- 缺点
- 从代码层面来看,使用装饰器模式会出现更多的代码,更多的类,增加程序复杂性
- 动态装饰时,多层装饰时会更复杂
更多推荐
已为社区贡献4条内容
所有评论(0)