装饰者模式 : 在不改变原有对象的基础上附加功能,动态的给一个对象添加或者撤销功能 (通过调用super的方法控制执行的顺序),相比生成子类更灵活。
1.装饰者模式应用场景
Java IO流,Mybatis的缓存框架,Spring中的Session等等。
2.装饰者模式优缺点
优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个功能按想要的顺序执行,以实现不同效果。
缺点:更多的类,使程序复杂
3.装饰者模式定义
(1)抽象组件:定义一个抽象接口(或者抽象类),来规范准备附加功能的类
(2)具体组件:将要被附加功能的类,实现抽象构件角色接口
(3)抽象装饰者:持有对具体构件角色的引用并定义与抽象构件角色一致的接口
(4)具体装饰:实现抽象装饰者角色,负责对具体构件添加额外功能。
说完装饰者的特点后,我这边写个案例帮助大家理解装饰器模式在实际项目种如何运用
案例: 在原有的网关功能基础上扩展新功能
需求分析:网关接口原来的功能,主要是解析数据,对部分数据做脱敏处理,随着业务的发展现在需要在原来功能的基础上扩展新的功能,包括接口的限流操作,接口日志的收集
通过装饰器模式的改造类图的变化如下
代码实现部分
1.定义一个抽象类(原来的代码)
package com.brian.decorative.service; /** * @program: architect * @author: Brian Huang * @create: 2019-05-14 21:08 **/ public abstract class BaseGateway { public abstract void service(); }
2.定义被装饰角色 (原来的代码)
package com.brian.decorative.service.impl; import com.brian.decorative.service.BaseGateway; import lombok.extern.slf4j.Slf4j; /** * @program: architect * @author: Brian Huang * @create: 2019-05-14 21:15 **/ @Slf4j public class DesensitizationComponent extends BaseGateway { @Override public void service() { log.info("1-->>> 网关中获取基本的操作,数据脱敏..."); } }
3.定义抽象装饰角色 (扩展的代码)
package com.brian.decorative.service; /** * @program: architect * @author: Brian Huang * @create: 2019-05-14 21:13 **/ public abstract class GatewayDecorate extends BaseGateway { private BaseGateway baseGateway; public GatewayDecorate(BaseGateway baseGateway) { this.baseGateway = baseGateway; } @Override public void service() { if(baseGateway !=null){ baseGateway.service(); } } }
4.定义具体装饰角色(扩展的代码)
package com.brian.decorative.service.impl; import com.brian.decorative.service.BaseGateway; import com.brian.decorative.service.GatewayDecorate; import lombok.extern.slf4j.Slf4j; /** * @program: architect * @author: Brian Huang * @create: 2019-05-14 21:16 **/ @Slf4j public class LimitComponent extends GatewayDecorate { public LimitComponent(BaseGateway baseGateway) { super(baseGateway); } @Override public void service() { super.service(); log.info("3-->>> 网关中新增API接口的限流.."); } } ---------- package com.brian.decorative.service.impl; import com.brian.decorative.service.BaseGateway; import com.brian.decorative.service.GatewayDecorate; import lombok.extern.slf4j.Slf4j; /** * @program: architect * @author: Brian Huang * @create: 2019-05-14 21:16 **/ @Slf4j public class LogComponent extends GatewayDecorate { public LogComponent(BaseGateway baseGateway) { super(baseGateway); } @Override public void service() { super.service(); log.info("2-->>> 网关中新增日志收集.."); } }
5.使用工厂获取装饰类(扩展的代码)
package com.brian.decorative.factory; import com.brian.decorative.service.BaseGateway; import com.brian.decorative.service.impl.DesensitizationComponent; import com.brian.decorative.service.impl.LimitComponent; import com.brian.decorative.service.impl.LogComponent; /** * @program: architect * @author: Brian Huang * @create: 2019-05-14 21:38 **/ public class FactoryGateway { public static BaseGateway getBaseGateway() { return new LimitComponent(new LogComponent(new DesensitizationComponent())); } public static void main(String[] args) { FactoryGateway.getBaseGateway().service(); } }
测试结果:
责任链与装饰模式区别:
1.责任链模式下,每个被调用者都持有下一个被调用者的引用,客户端只需要发起一次调用即可,整个过程是链式的调用,从前往后执行。
2.装饰者模式下,持有被装饰的对象,并具备被装饰者的行为,对其行为进行补充增强,整个过程是像包裹住的洋葱,从内层一层向外调用。
装饰器与适配器的区别:
其实适配器模式也是一种包装(Wrapper)模式,它们看似都是起到包装一个类或对象的作用,但是它们使用的目的非常不一样:
1、适配器模式的意义是要将一个接口转变成另外一个接口,它的目的是通过改变接口来达到重复使用的目的
2、装饰器模式不要改变被装饰对象的接口,而是恰恰要保持原有的借口哦,但是增强原有接口的功能,或者改变元有对象的处理方法而提升性能
博客参考:https://www.cnblogs.com/xrq730/p/4908940.html