文章目录

  • 什么是装饰器模式
    • 优点
    • 缺点
    • 使用场景
  • 装饰器模式和代理模式的区别
  • 装饰器的简单实现
  • 装饰器模式实战
  • 小结

什么是装饰器模式

装饰器模式(Decorator Pattern): 在不改变对象自身的基础上,在程序运行期间给对象动态的添加职责;

感觉有点儿类似于继承,不改变父类,子类可拓展功能;

优点
  1. 装饰类和被装饰类可以独立发展,不会相互耦合
  2. 相比于继承,更加的轻便、灵活
  3. 可以动态扩展一个实现类的功能,不必修改原本代码
缺点
  1. 会产生很多的装饰类,增加了系统的复杂性。
  2. 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
使用场景
  1. 对已有的目标功能存在不足,需要增强时,扩展类的功能。
  2. 动态增加功能,动态撤销

装饰器模式和代理模式的区别

  • 代理是全权代理,目标根本不对外,全部由代理类来完成;装饰是增强,是辅助,目标仍然可以自行对外提供服务,装饰器只起增强作用。
  • 装饰器模式强调的是:增强、新增行为;代理模式强调的是:对代理的对象施加控制,但不对对象本身的功能进行增强
  • 装饰器模式:生效的对象还是原本的对象;代理模式:生效的是新的对象(代理对象)

装饰器的简单实现

场景:天气太热了,喝点儿冰水解解暑;加点儿柠檬片,让果汁好喝点儿

先定义一个喝水的接口

public interface Drink {/*** 喝水*/void drink();
}

写一个接口的实现

public class DrinkWater implements Drink {@Overridepublic void drink() {System.out.println("喝水");}}

一个简单的装饰器

public class DrinkDecorator implements Drink {private final Drink drink;public DrinkDecorator(Drink drink) {this.drink = drink;}@Overridepublic void drink() {System.out.println("先加点儿柠檬片");drink.drink();}}

开始测试

public class DrinkMain {public static void main(String[] args) {Drink drink = new DrinkWater();drink = new DrinkDecorator(drink);drink.drink();}
}

运行结果

先加点儿柠檬片
喝水

一个简单的装饰器模式例子就写完了

看起来和代理模式(代理设计模式) 真是太像了,简直一摸一样

装饰器模式实战

场景: 项目一期开发的时候,并没有给鉴权部分设置缓存;二期开发考虑到性能问题,想要给鉴权部分加上缓存,这里就选择了使用装饰器模式进行处理;

ps: 小白一枚,第一次见到这个操作;感觉很新奇,了解一下装饰器模式,这篇文章就出来了

这里使用的缓存是spring的 spring-cache,不了解没关系,知道几个注解什么意思就行

@Cacheable 表示要对方法返回值进行缓存

@CacheEvict 删除缓存注解

为了简洁,以下代码均为伪代码

首先,需要一个权限的接口和实现类

public interface IDataAccessor {/*** 根据部门上级 id 获取所有子集部门*/Set<Long> deptFindAllChildrenByParentIds(Collection<Long> parentIds);/*** 获取数据范围内的部门*/Set<Long> deptFindScopeById(Long userId);

实现类(注意这里加了@Service, 交给spring处理)

@Service
public class ScopeDataAccessorImpl implements IDataAccessor {@Autowiredprivate IDepartmentService departmentService;@Autowiredprivate INodeScopeService nodeScopeService;@Overridepublic Set<Long> deptFindAllChildrenByParentIds(Collection<Long> parentIds) {Set<Long> result = new HashSet<>();departmentService.departmentChildren(parentIds, result);return result;}@Overridepublic Set<Long> deptFindScopeById(Long userId) {return nodeScopeService.deptFindScopeById(userId);}
}

接下来就是对之前的代码进行装饰,定义一个装饰器的实现类

(这个类没有 @Component, 没有直接交给spring管理;加了注解会报错:找到了2个bean)

public class DataAccessorDecorator implements IDataAccessor {private final IDataAccessor iDataAccessor;public DataAccessorDecorator(IDataAccessor iDataAccessor) {this.iDataAccessor = iDataAccessor;}@Cacheable(cacheNames = "dept:parentId", key = "#p0", sync = true)@Overridepublic Set<Long> deptFindAllChildrenByParentIds(Collection<Long> parentIds) {return iDataAccessor.deptFindAllChildrenByParentIds(parentIds);}@Cacheable(cacheNames = "dept:scope:userId", key = "#p0", sync = true)@Overridepublic Set<Long> deptFindScopeById(Long userId) {return iDataAccessor.deptFindScopeById(nodeId,userId);}
}

接下来还需要将这个装饰器的类注册到spring中

@Configuration
@ConditionalOnBean({IDataAccessor.class})
public class Config {@Bean@ConditionalOnBean({IDataAccessor.class})public DataAccessorDecorator dataAccessorDecorator(IDataAccessor iDataAccessor) {return new DataAccessorDecorator(iDataAccessor);}
}

使用的时候直接使用装饰器类就好了

@Service
public class UserService {@AutowiredDataAccessorDecorator scopeDataAccessor;public Set<Long> deptFindAllChildrenByParentIds(Collection<Long> parentIds) {return scopeDataAccessor.deptFindAllChildrenByParentIds(parentIds);}public Set<Long> deptFindScopeById(Long userId) {return scopeDataAccessor.deptFindScopeById(userId);}}

根据业务,维护缓存更新即可;这里使用的监听部门和员工的变更事件

@Component
public class DataScopeEvict {/*** 清空部门相关缓存*/@CacheEvict(cacheNames = {"dept:parentId"}, allEntries = true)public void department() {}/*** 清空用户相关缓存*/@CacheEvict(cacheNames = {"dept:scope:userId"}, allEntries = true)public void user() {}
}
@Component
public class ScopeDataEventListener {@Autowiredprivate DataScopeEvict evict;/*** 监听部门变更事件*/@EventListenerpublic void departmentEvent(DepartmentChangeEvent event) {// 1 增加 2 删除 3 上级部门变更evict.department();}/*** 监听user变更事件*/@EventListenerpublic void userEvent(UserChangeEvent event) {// 2 删除 3 主部门变更if (event.getType().equals(2) || event.getType().equals(3)) {evict.user();}}
}

以上就是一个将装饰器模式应用到实际项目的例子;

小结

在这个例子中,使用装饰器模式增强了原本的代码,不修改之前的代码,之前的代码也能正确提供服务,只不过不修改的话,就无法使用缓存;只要方法名一样,只需修改注入的字段就可以升级完成,还是很方便的

Java设计模式(六)装饰器模式-与代理模式的区别-项目实战应用相关推荐

  1. (设计模式七)java设计模式之装饰器模式

    一.简介: 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.这种模式创建了一个装饰类 ...

  2. java设计模式之 装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...

  3. java设计模式之装饰器模式

    一.装饰器模式简介 装饰器模式可以动态给一个对象添加一些额外的职责,同时又不改变其结构.就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.这种模式创建了一个装饰 ...

  4. Java 设计模式之装饰器模式

    装饰器模式用于给原有对象增加新功能的场景, 拿食物冰淇淋,香草巧克力作为例子,给冰淇淋加香草,或者加巧克力,或者加香草和巧克力. 首先定义一个食物接口: /*** 装饰类和被装饰类共同继承的抽象类* ...

  5. java设计模式之装饰器模式(包装器模式)

    显然设计模式往往追求开闭原则,所以往往是面向接口编程,那么万事万物就是先写接口,把需求弄出来,这里以一辆车子在陆地上跑为基础,对它进行装饰,使它可以具备更多的"功能",达到装饰的效 ...

  6. java设计模式之为别人做嫁衣----代理模式

    2019独角兽企业重金招聘Python工程师标准>>> 7.1为别人做嫁衣 "小菜,今天见这个叫娇娇的美女见得如何呀?"大鸟一回家来就问小菜. "唉,别 ...

  7. 设计模式11_装饰器

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装 ...

  8. JAVA开发的23种设计模式之 —  装饰器模式 代理器模式

    装饰器模式 概述 : 动态的给一个对象添加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更加灵活 维基百科解释 : 通过使用修饰模式,可以在运行时扩充一个类的功能.原理是 :增加一个修饰类包裹 ...

  9. 【设计模式】--- 装饰器模式、静态代理模式和动态代理模式

    文章目录 1 引子 2 业务场景介绍 3 静态代理模式 4 装饰器模式 5 动态代理模式 5.1 Proxy --- 具体的代理对象生成组件 5.2 InvocationHandler --- 封装被 ...

  10. 设计模式之结构型模式:适配器模式、桥接模式、组合模式、装饰器模式、代理模式、

    文章目录 什么是结构型模式 适配模式 适配器的数据结构 适配器的实现 缺省适配器 适配器优缺点 适配器模式的使用环境 桥接模式 桥接模式数据结构 桥接模式的实现 桥接模式和适配器模式的联用 桥接模式的 ...

最新文章

  1. UI设计师必备技能,看看你都学会了吗?
  2. CVPR14与图像视频检索相关的论文
  3. 《解释的工具:生活中的经济学原理 读书笔记6》
  4. ASP.NET Core 网站运行时修改设置如何自动生效
  5. POJ1201-Intervals【差分约束,负环,SPFA】
  6. PPPOE拨号上网流程及密码窃取具体实现
  7. 泛微协同办公平台E-cology8.0版本后台维护手册--组织权限中心
  8. win10下装黑苹果双系统_win10下安装双系统:黑苹果10.13.5(17F77)教程!
  9. 新加坡10月新人扎堆结婚,只要生娃政府就发3000新币
  10. 微信小程序实现类似微信评论区回复组件(mpx)
  11. linux压缩解压工具效率,linux压缩解压工具
  12. Information Gain 计算 python实现
  13. 国内有那些chia矿池,chia矿池排行那几家比较靠谱
  14. UOJ#311. 【UNR #2】积劳成疾
  15. Excel按倍率一键调整当前表格的行高
  16. php实现阿里云视频合成
  17. 数据结构哈夫曼树实现26个英文字符的编码和译码
  18. easyUI tree 自定义图标
  19. pytorch中nn.Embedding和nn.LSTM和nn.Linear
  20. CF808E Selling Souvenirs

热门文章

  1. DAY1(02-HTML标签(上))
  2. 51采集温度电压电流+LCD1602显示
  3. 「短篇小说」灵囚 540 天
  4. 小米5.0以上设备最完美激活xposed框架的流程
  5. PostgreSQL - 一文看懂explain
  6. iOS内购提示无效ID : .paymentInvalid
  7. LTspice中 Voltage Controlled Switches的使用方法
  8. 对偶的应用及拓展(Duality Uses and Correspondences)
  9. 中海岸扫盲之--什么是不干胶
  10. 谷歌 AI 团队用 GAN 模型合成异形生物体