装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下:

装饰器模式的应用场景:

1、需要扩展一个类的功能。

2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)

缺点:产生过多相似的对象,不易排错!

实例一:

Source类是被装饰类,Decorator类是一个装饰类,可以为Source类动态的添加一些功能,代码如下:

public interface Sourceable {public void flyMethod();
}***************************************************
public class Source implements Sourceable {@Overridepublic void flyMethod() {System.out.println("被装饰的类:基类");}
}
***************************************************
public abstract class Decorate implements Sourceable {private Source source;public Decorate() {}public Decorate(Source source) {this.source = source;}public Source getSource() {return source;}public void setSource(Source source) {this.source = source;}@Overridepublic abstract void flyMethod();
}
***************************************************
public class FlyDecorate extends Decorate {public FlyDecorate(Source source) {super(source);}@Overridepublic void flyMethod() {this.getSource().flyMethod();this.runMethod();}public void runMethod() {System.out.println("可以跑");}
}

测试:

public class MainClass {public static void main(String[] args) {Source source = new Source();Decorate decorate = new FlyDecorate(source);decorate.flyMethod();}
}输出结果被装饰的类:基类
可以跑

实例二:

Car接口 ,RunCar是被装饰类,CarDecorator装饰器抽象类或接口,FlyCarDecorator 具体的装饰器,给RunCar添加飞功能。

public interface Car {public void show();
}**************************************************************
基本类:被装饰的类
public class RunCar implements Car {@Overridepublic void show() {this.run();}public void run() {System.out.println("可以跑");}
}
**************************************************************
抽象装饰器:
public abstract class CarDecorator implements Car {private Car car;public CarDecorator(Car car) {this.car = car;}public CarDecorator() {}public Car getCar() {return car;}public void setCar(Car car) {this.car = car;}@Overridepublic abstract void show() ;
}**************************************************************
装饰器:给RunCar添加"飞"功能
public class FlyCaDecoratorr extends CarDecorator {public FlyCaDecoratorr(Car car) {super(car);}@Overridepublic void show() {this.getCar().show();this.fly();}public void fly() {System.out.println("可以飞");}
}
**************************************************************
装饰器:给RunCar添加“游泳”功能
public class SwimCarDecorator extends CarDecorator {public SwimCarDecorator(Car car) {super(car);}@Overridepublic void show() {this.getCar().show();this.swim();}public void swim() {System.out.println("可以游泳");}
}**************************************************************

测试:

public class MainClass {public static void main(String[] args) {Car runCar = new RunCar();runCar.show();System.out.println("***********************");Car carDecorator = new FlyCaDecoratorr(runCar);carDecorator.show();System.out.println("_______________________");Car carDecorator1 = new SwimCarDecorator(carDecorator);carDecorator1.show();}
}输出结果:
可以跑
***********************
可以跑
可以飞
_______________________
可以跑
可以飞
可以游泳

实战二

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

这里使用的缓存是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);}
}

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

@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();}}
}

一切准备就绪,使用的时候直接使用装饰器类就好了

@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);}}

定义事件并发布事件

public class UserChangeEvent {private String type;public String getType() {return type;}public UserChangeEvent setType(String type) {this.type = type;return this;}
}public class DepartmentChangeEvent {
}
@Autowired
private ApplicationContext context;//上下文,用于发布事件void test() {UserChangeEvent event = new UserChangeEvent();//构建事件
event.setType("3");
this.context.publishEvent(event); //发布事件
}

@Autowired ApplicationEventPublisher applicationEventPublisher;

applicationEventPublisher.publishEvent(new ErpEvent(baseId));

ApplicationEventPublisher 或者ApplicationContext都可以执行,context实现了eventPublicsher接口

实例三

咖啡+调料订单

public abstract class Drink {protected String description;protected float price;public float getPrice() {return price;}public Drink setPrice(float price) {this.price = price;return this;}public String getDescription() {return description + " " + getPrice();}public Drink setDescription(String description) {this.description = description;return this;}// 统计金额abstract float cost();
}
public class Decaf extends Drink{public Decaf() {setDescription("无因咖啡");setPrice(0.8f);}@Overridefloat cost() {return getPrice();}
}public class ShortBlack extends Drink{public ShortBlack() {setDescription("小特黑咖啡");setPrice(0.5f);}@Overridefloat cost() {return 0;}
}public class LongBlack extends Drink{public LongBlack() {setDescription("美式咖啡");setPrice(0.1f);}@Overridefloat cost() {return getPrice();}
}public class Espresso extends Drink {public Espresso() {setDescription("浓缩咖啡");setPrice(0.6f);}@Overridefloat cost() {return getPrice();}
}
public class Decorator extends Drink {protected Drink drink;public Decorator(Drink drink) {this.drink = drink;}@Overridefloat cost() {return drink.getPrice() + getPrice();}@Overridepublic String getDescription() {return description + " " + getPrice() + "&&" + drink.getDescription();}
}
public class Milk extends Decorator{public Milk(Drink drink) {super(drink);setDescription("牛奶");setPrice(0.7f);}}public class Soy extends Decorator{public Soy(Drink drink) {super(drink);setDescription("豆奶");setPrice(0.2f);}}public class Chocolate extends Decorator{public Chocolate(Drink drink) {super(drink);setDescription("巧克力");setPrice(0.4f);}}
public class MainClient {public static void main(String[] args) {// 装饰者模式下的订单:2 份巧克力+一份牛奶的 LongBlackDrink drink = new LongBlack();System.out.println("描述:"+ drink.getDescription());System.out.println("费用:"+ drink.cost());System.out.println("---------");Milk milk = new Milk(drink);System.out.println("加一份牛奶");System.out.println("描述:"+ milk.getDescription());System.out.println("费用:"+ milk.cost());System.out.println("-----------");Chocolate chocolate = new Chocolate(milk);System.out.println("加一份巧克力");System.out.println("描述:"+ chocolate.getDescription());System.out.println("费用:"+ chocolate.cost());System.out.println("-----------");}
}// 打印
描述:美式咖啡 0.1
费用:0.1
---------
加一份牛奶
描述:牛奶 0.7&&美式咖啡 0.1
费用:0.8
-----------
加一份巧克力
描述:巧克力 0.4&&牛奶 0.7&&美式咖啡 0.1
费用:1.1
-----------Process finished with exit code 0

设计模式:Decorator--装饰器模式相关推荐

  1. python中的装饰器、装饰器模式_python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  2. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  3. 设计模式学习----装饰器模式

    这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大 ...

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

    go设计模式之装饰器模式 再写这篇文章时,我已经看了很多其他人发表的类似文章,大概看了这么多吧. 亓斌的设计模式-装饰者模式(Go语言描述) jeanphorn的Golang设计模式之装饰模式 七八月 ...

  5. 零基础学习设计模式之装饰器模式(配套视频)

    零基础学习设计模式之装饰器模式 定义 在不改变目标结构的情况下,动态的给对象增加功能 举例 如房子装修.相片加相框等,都是装饰器模式. 基本组件 抽象构件(Component)角色:定义一个抽象接口以 ...

  6. 详解设计模式:装饰器模式

    装饰器模式(Decorator Pattern)也称为包装模式(Wrapper Pattern),是 GoF 的 23 种设计模式中的一种结构型设计模式.装饰器模式 是指在不改变原有对象的基础之上,将 ...

  7. Java —— Decorator 装饰器模式

    文章目录 Java -- Decorator 装饰器模式 简介 用处 简单例子 结构 代码 涉及角色 相关的设计模式 应用实例 优点 缺点 使用场景 注意事项 代码 Java -- Decorator ...

  8. 设计模式之装饰器模式详解

    设计模式之装饰器模式详解 文章目录 设计模式之装饰器模式详解 一.什么是装饰器模式 二.装饰器模式的角色组成 三.装饰器模式通用写法示例 四.装饰器模式业务中的应用举例 五.装饰器模式优缺点 一.什么 ...

  9. 【设计模式】装饰器模式的使用

    问题来源 我们在进行软件系统设计的时候,有一些业务(如下图,一些通用的非功能性需求)是多个模块都需要的,是跨越模块的.把它们放到什么地方呢? 最简单的办法就是把这些通用模块的接口写好,让程序员在实现业 ...

  10. javascript设计模式之装饰器模式(结构型模式)

    javascript设计模式之装饰器模式 js的设计模式分为创建型模式,结构型模式和行为模式 结构模式描述了如何组合对象以提供新的功能. 装饰器模式是一种常见的结构型模式,我们可以以一个基础对象为基础 ...

最新文章

  1. LabVIEW设置应用程序显示标签透明
  2. chrome 硬件渲染(GPU Accelerated Compositing in Chrome)
  3. C# Sato CL4NX打印机发送SBPL指令打印表面信息、RFID芯片数据写入
  4. Unsupported ONNX opset version: 11
  5. Android系统,动态找出一个包下所有的类
  6. Serverless五大优势,成本和规模不是最重要的,这点才是架构
  7. mysqldump 的常用参数。
  8. 飞鸽传书完全不知道这是什么
  9. spring boot 整合 mybatis
  10. 剑指offer——8.二叉树的下一个节点
  11. 武汉经济技术开发区建筑业企业高管人才奖励认定时间、条件、材料、程序指导
  12. python url解码_使用python对url编码解码
  13. #MoreThanCode:社会正义技术
  14. 什么是WEB应用waf防火墙和DDOS高防IP?
  15. 为了结婚领证,我做了个「一键结婚」插件
  16. python中math函数_python中math模块函数
  17. 最新多用途的APP软件业务介绍官网模板源码
  18. 触摸操作(单手旋转双手缩放)
  19. 软件工程作业(流程图,盒图)
  20. 51单片机案例实操 -- 倒车雷达

热门文章

  1. 安装武器(pycharm,Anaconda)
  2. 推荐几门微信小程序免费学习的课程
  3. 基于MISRA-C和VS Code的代码静态检查的开源解决方案
  4. What is a nuclear reactor?(核反应堆是什么)
  5. 【历史上的今天】5 月 3 日:戴尔公司成立;“深蓝”再战象棋冠军;计算机先驱诞生日
  6. 算法竞赛中文件的输入输出
  7. 12306 订票助手 1.3
  8. 手把手教你用pytorch实现k折交叉验证,解决类别不平衡
  9. 项目七 网络打印的配置与管理
  10. 【吃灰板子捡起来】字符设备驱动开发实验