首页
设计模式
常用bat文件
Maven教程
前端公共工具类
mongodb
算法收集与实现
Sqlserver常用知识
Oracle常用知识梳理
更多……
申请加入课程
单例模式
外观模式
工厂模式
建造者模式
原型模式
适配器模式
桥接模式
过滤器模式
组合模式
装饰器模式
享元模式
代理模式
责任链模式
命令模式
解释器模式
迭代器模式
中介者模式
备忘录模式
观察者模式
状态模式
空对象模式
策略模式
模板模式
访问者模式
MVC 模式
业务代表模式
组合实体模式
数据访问对象模式
前端控制器模式
拦截过滤器模式
服务定位器模式
传输对象模式
装饰器模式
星辰
2018-09-17
0
0
175
人
0
人评论
0
人举报
# 装饰器模式 > * 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 * 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。 ## 意图: > 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。 ## 优点: > 饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。 ## 使用场景 > * 1、扩展一个类的功能。 * 2、动态增加功能,动态撤销。 ## 类图  * Component为统一接口,也是装饰类和被装饰类的基本类型。 * ConcreteComponent为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类。 * Decorator是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。而Decorator本身,通常采用默认实现,他的存在仅仅是一个声明:我要生产出一些用于装饰的子类了。而其子类才是赋有具体装饰效果的装饰产品类。 * ConcreteDecorator是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent,从而对其进行装饰。 ## 装饰类代码案例 ### 简单的装饰类实现案例 ``` package com.noteshare.designPatterns.decorator.demo1; /** * 基础接口 -组件 */ public interface Component { public void biu(); } package com.noteshare.designPatterns.decorator.demo1; /** * 具体实现类 */ public class ConcretComponent implements Component { public void biu() { System.out.println("biubiubiu"); } } package com.noteshare.designPatterns.decorator.demo1; /** * 装饰类 */ public class Decorator implements Component { public Component component; public Decorator(Component component) { this.component = component; } public void biu() { this.component.biu(); } } package com.noteshare.designPatterns.decorator.demo1; /** * 具体装饰类 */ public class ConcreteDecorator extends Decorator { public ConcreteDecorator(Component component) { super(component); } public void biu() { System.out.println("ready?go!"); this.component.biu(); } } package com.noteshare.designPatterns.decorator.demo1; /** * 这样一个基本的装饰器体系就出来了,当我们想让Component在打印之前都有一个ready?go!的提示时, * 就可以使用ConcreteDecorator类了。具体方式如下: */ public class Client { public static void main(String[] args) { // 使用装饰器 Component component = new ConcreteDecorator(new ConcretComponent()); component.biu(); } } ``` ### 为何使用装饰器模式 > * 一个设计模式的出现一定有他特殊的价值。仅仅看见上面的结构图你可能会想,为何要兜这么一圈来实现?仅仅是想要多一行输出,我直接继承ConcretComponent,或者直接在另一个Component的实现类中实现不是一样吗? * 首先,装饰器的价值在于装饰,他并不影响被装饰类本身的核心功能。在一个继承的体系中,子类通常是互斥的。比如一辆车,品牌只能要么是奥迪、要么是宝马,不可能同时属于奥迪和宝马,而品牌也是一辆车本身的重要属性特征。但当你想要给汽车喷漆,换坐垫,或者更换音响时,这些功能是互相可能兼容的,并且他们的存在不会影响车的核心属性:那就是他是一辆什么车。这时你就可以定义一个装饰器:喷了漆的车。不管他装饰的车是宝马还是奥迪,他的喷漆效果都可以实现。 * 再回到这个例子中,我们看到的仅仅是一个ConcreteComponent类。在复杂的大型项目中,同一级下的兄弟类通常有很多。当你有五个甚至十个ConcreteComponent时,再想要为每个类都加上“ready?go!”的效果,就要写出五个子类了。毫无疑问这是不合理的。装饰器模式在不影响各个ConcreteComponent核心价值的同时,添加了他特有的装饰效果,具备非常好的通用性,这也是他存在的最大价值。 ### 装饰类实例代码 > 案例:需求大致是这样:采用sls服务监控项目日志,以Json的格式解析,所以需要将项目中的日志封装成json格式再打印。现有的日志体系采用了log4j + slf4j框架搭建而成。调用起来是这样的: ``` private static final Logger logger = LoggerFactory.getLogger(Component.class); logger.error(string); ``` > 这样打印出来的是毫无规范的一行行字符串。在考虑将其转换成json格式时,我采用了装饰器模式。目前有的是统一接口Logger和其具体实现类,我要加的就是一个装饰类和真正封装成Json格式的装饰产品类。具体实现代码如下: ``` package com.noteshare.designPatterns.decorator.demo2; import org.slf4j.Logger; import org.slf4j.Marker; /** * logger decorator for other extension * this class have no specific implementation * just for a decorator definition */ public class DecoratorLogger implements Logger { public Logger logger; public DecoratorLogger(Logger logger) { this.logger = logger; } @Override public void info(String msg) { // TODO Auto-generated method stub } @Override public void error(String msg) { // TODO Auto-generated method stub } @Override public String getName() { // TODO Auto-generated method stub return null; } @Override public boolean isTraceEnabled() { // TODO Auto-generated method stub return false; } @Override public void trace(String msg) { // TODO Auto-generated method stub } @Override public void trace(String format, Object arg) { // TODO Auto-generated method stub } @Override public void trace(String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void trace(String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void trace(String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isTraceEnabled(Marker marker) { // TODO Auto-generated method stub return false; } @Override public void trace(Marker marker, String msg) { // TODO Auto-generated method stub } @Override public void trace(Marker marker, String format, Object arg) { // TODO Auto-generated method stub } @Override public void trace(Marker marker, String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void trace(Marker marker, String format, Object... argArray) { // TODO Auto-generated method stub } @Override public void trace(Marker marker, String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isDebugEnabled() { // TODO Auto-generated method stub return false; } @Override public void debug(String msg) { // TODO Auto-generated method stub } @Override public void debug(String format, Object arg) { // TODO Auto-generated method stub } @Override public void debug(String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void debug(String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void debug(String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isDebugEnabled(Marker marker) { // TODO Auto-generated method stub return false; } @Override public void debug(Marker marker, String msg) { // TODO Auto-generated method stub } @Override public void debug(Marker marker, String format, Object arg) { // TODO Auto-generated method stub } @Override public void debug(Marker marker, String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void debug(Marker marker, String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void debug(Marker marker, String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isInfoEnabled() { // TODO Auto-generated method stub return false; } @Override public void info(String format, Object arg) { // TODO Auto-generated method stub } @Override public void info(String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void info(String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void info(String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isInfoEnabled(Marker marker) { // TODO Auto-generated method stub return false; } @Override public void info(Marker marker, String msg) { // TODO Auto-generated method stub } @Override public void info(Marker marker, String format, Object arg) { // TODO Auto-generated method stub } @Override public void info(Marker marker, String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void info(Marker marker, String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void info(Marker marker, String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isWarnEnabled() { // TODO Auto-generated method stub return false; } @Override public void warn(String msg) { // TODO Auto-generated method stub } @Override public void warn(String format, Object arg) { // TODO Auto-generated method stub } @Override public void warn(String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void warn(String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void warn(String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isWarnEnabled(Marker marker) { // TODO Auto-generated method stub return false; } @Override public void warn(Marker marker, String msg) { // TODO Auto-generated method stub } @Override public void warn(Marker marker, String format, Object arg) { // TODO Auto-generated method stub } @Override public void warn(Marker marker, String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void warn(Marker marker, String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void warn(Marker marker, String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isErrorEnabled() { // TODO Auto-generated method stub return false; } @Override public void error(String format, Object arg) { // TODO Auto-generated method stub } @Override public void error(String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void error(String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void error(String msg, Throwable t) { // TODO Auto-generated method stub } @Override public boolean isErrorEnabled(Marker marker) { // TODO Auto-generated method stub return false; } @Override public void error(Marker marker, String msg) { // TODO Auto-generated method stub } @Override public void error(Marker marker, String format, Object arg) { // TODO Auto-generated method stub } @Override public void error(Marker marker, String format, Object arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void error(Marker marker, String format, Object... arguments) { // TODO Auto-generated method stub } @Override public void error(Marker marker, String msg, Throwable t) { // TODO Auto-generated method stub } } package com.noteshare.designPatterns.decorator.demo2; import org.apache.commons.lang.exception.ExceptionUtils; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 以看到,在JsonLogger中,对于Logger的各种接口,我都用JsonObject对象进行一层封装。在打印的时候,最终还是调用原生接口logger. * error(string), 只是这个string参数已经被我们装饰过了。如果有额外的需求,我们也可以再写一个函数去实现。 * 比如error(Exception e),只传入一个异常对象,这样在调用时就非常方便了。 * 另外,为了在新老交替的过程中尽量不改变太多的代码和使用方式。我又在JsonLogger中加入了一个内部的工厂类JsonLoggerFactory * (这个类转移到DecoratorLogger中可能更好一些),他包含一个静态方法,用于提供对应的JsonLogger实例。最终在新的日志体系中, * 使用方式如下: * private static final Logger logger = JsonLoggerFactory.getLogger(Component.class); logger.error(string); * 他唯一与原先不同的地方,就是LoggerFactory -> JsonLoggerFactory,这样的实现,也会被更快更方便的被其他开发者接受和习惯。 */ public class JsonLogger extends DecoratorLogger { public JsonLogger(Logger logger) { super(logger); } @Override public void info(String msg) { JSONObject result = composeBasicJsonResult(); result.put("MESSAGE", msg); logger.info(result.toString()); } @Override public void error(String msg) { JSONObject result = composeBasicJsonResult(); result.put("MESSAGE", msg); logger.error(result.toString()); } public void error(Exception e) { JSONObject result = composeBasicJsonResult(); result.put("EXCEPTION", e.getClass().getName()); String exceptionStackTrace = ExceptionUtils.getStackTrace(e); result.put("STACKTRACE", exceptionStackTrace); logger.error(result.toString()); } public static class JsonLoggerFactory { @SuppressWarnings("rawtypes") public static JsonLogger getLogger(Class clazz) { Logger logger = LoggerFactory.getLogger(clazz); return new JsonLogger(logger); } } private JSONObject composeBasicJsonResult() { // 拼装了一些运行时信息 return null; } } ```
所有评论列表
点我发表评论