基础部分
装饰者模式的类图
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
装饰者模式的简单入门案例
来看一个这样的场景,有些小伙伴可能在上班路上碰到卖煎饼的路边摊,都会顺带一个到公司茶水间吃早餐。卖煎饼的大姐可以给你的煎饼加鸡蛋,也可以加香肠.
用装饰者实现计算总价:
类图:
在这里插入图片描述
煎饼类
public class Battercake {
protected String getMsg(){
return "煎饼";
}
public int getPrice(){
return 5;
}
}
基础套餐
public class BaseBattercake extends Battercake {
@Override
protected String getMsg() {
return "煎饼";
}
@Override
protected int getPrice() {
return 5;
}
}
抽象装饰类
/**
* Title: BattercakeDecorator
* Description: 加蛋糕的套餐
*
* @author hfl
* @version V1.0
* @date 2020-05-31
*/
public abstract class BattercakeDecorator extends Battercake {
private Battercake battercake;
public BattercakeDecorator(Battercake battercake) {
this.battercake = battercake;
}
//、用于扩展一个类的功能或给一个类添加附加职责。
protected abstract void doSomething();
@Override
protected String getMsg() {
return this.battercake.getMsg();
}
@Override
protected int getPrice() {
return this.battercake.getPrice() ;
}
}
鸡蛋装饰者
/**
* Title: EggDecorator
* Description: 鸡蛋装饰者
*
* @author hfl
* @version V1.0
* @date 2020-05-31
*/
public class EggDecorator extends BattercakeDecorator {
public EggDecorator(Battercake battercake) {
super(battercake);
}
@Override
protected void doSomething() {
}
@Override
protected String getMsg() {
return super.getMsg()+"+1个鸡蛋";
}
@Override
protected int getPrice() {
return super.getPrice()+ 1;
}
}
/**
* Title: SausageDecorator
* Description: 香肠装饰者
*
* @author hfl
* @version V1.0
* @date 2020-05-31
*/
public class SausageDecorator extends BattercakeDecorator {
public SausageDecorator(Battercake battercake) {
super(battercake);
}
@Override
protected void doSomething() {
}
@Override
protected String getMsg() {
return super.getMsg() + "1根香肠";
}
@Override
protected int getPrice() {
return super.getPrice() + 2;
}
}
测试类:
public class BattercakeTest {
public static void main(String[] args) {
Battercake battercake;
//路边摊买一个煎饼
battercake = new BaseBattercake();
//煎饼有点小,想再加一个鸡蛋
battercake = new EggDecorator(battercake);
//再加一个鸡蛋
battercake = new EggDecorator(battercake);
//很饿,再加根香肠
battercake = new SausageDecorator(battercake);
//跟静态代理最大区别就是职责不同
//静态代理不一定要满足is-a 的关系
//静态代理会做功能增强,同一个职责变得不一样
//装饰器更多考虑是扩展
System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice());
}
}
运行结果:
在这里插入图片描述
高级部分
装饰者模式的本质
在这里插入图片描述 在这里插入图片描述怎么理解本质说的这2个方面:
类的层面考虑:横向扩展(动态扩展)--- 类比继承
我们如果有个类,有一些方法,而如果需要扩展这个类的方法,可能想到的是继承,可是java是单继承,所以为了满足客户端的需求,又做到单一性原则,可能需要继承好几层。纵向的链路会特别长。
A(){}
B extends A{}
C extens B{}
...
而装饰者模式,相当于横向扩展,大多数情况下,只会继承一层,但是要将继承的类,放在属性上,通过构造函数注入。一个装饰者扩展了某个功能后,返回的外观还是和注入的类同一个父类,下一个装饰者可以将上一个装饰者注入到自己,然后实现自己的方法功能,调用起来就好像这个样子:
new A(new B( new C(....)))
这就是横向扩展,解决了java的单继承弊端,防止了继承的链路太长。
对象方法的层面考虑:为装饰者透明的增加功能,甚至可以控制功能访问 --- 类比AOP
我们用过spring开发的都知道,spring使用动态代理帮我们在类方法执行的前,中,后进行一些公共逻辑的提取,帮我们简化代码。
同样的: 装饰者模式可以通过装饰者增加功能,甚至给装饰前的对象织入自己的逻辑呢。
代码演示:
在这里插入图片描述
封装销售单的数据
public class SaleModel {
/**
* 销售的商品
*/
private String goods;
/**
* 销售的数量
*/
private int saleNum;
public String getGoods() {
return goods;
}
public void setGoods(String goods) {
this.goods = goods;
}
public int getSaleNum() {
return saleNum;
}
public void setSaleNum(int saleNum) {
this.saleNum = saleNum;
}
@Override
public String toString() {
return "SaleModel{" +
"goods='" + goods + '\'' +
", saleNum=" + saleNum +
'}';
}
}
商品销售管理的业务接口
public interface GoodSaleEbi {
/**
* 保存销售信息
* @param user 操作人员
* @param cunstomer 客户
* @param saleModel 销售数据
* @return 是否保存成功
*/
public boolean sale(String user, String cunstomer, SaleModel saleModel);
}
基本的业务实现对象
public class GoodSaleEbo implements GoodSaleEbi {
@Override
public boolean sale(String user, String cunstomer, SaleModel saleModel) {
System.out.println(user + "保存了," + cunstomer + "购买" + saleModel + "的销售数据");
return true;
}
}
抽象的装饰器
public abstract class Decorator implements GoodSaleEbi {
/**
* 持有被装饰的组件对象
*/
protected GoodSaleEbi ebi;
/**
* 通过构造方法传入被装饰的对象
* @param ebi 被装饰的对象
*/
public Decorator(GoodSaleEbi ebi) {
this.ebi = ebi;
}
}
实现权限控制的装饰器
/**
* 实现权限控制的装饰器
*/
public class CheckDecorator extends Decorator{
/**
* 通过构造方法传入被装饰的对象
*
* @param ebi 被装饰的对象
*/
public CheckDecorator(GoodSaleEbi ebi) {
super(ebi);
}
//权限控制逻辑
@Override
public boolean sale(String user, String cunstomer, SaleModel saleModel) {
if (!"张三".equals(user)){
System.out.println("对不起" + user + ",你没有保存销售单的权限");
return false;
}else{
return this.ebi.sale(user,cunstomer,saleModel);
}
}
}
实现日志记录
public class LogDecorator extends Decorator {
public LogDecorator(GoodSaleEbi ebi) {
super(ebi);
}
@Override
public boolean sale(String user, String cunstomer, SaleModel saleModel) {
//执行业务
boolean f = this.ebi.sale(user, cunstomer, saleModel);
//在执行业务功能后记录日志
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("日志记录:" + user + "于" + simpleDateFormat.format(new Date())
+ "时保存了一条销售记录,客户是:" + cunstomer + ",购买记录是:" + saleModel);
return f;
}
}
测试:client
public class client {
public static void main(String[] args) {
//得到业务接口,组合装饰器
GoodSaleEbi ebi = new CheckDecorator(new LogDecorator(new GoodSaleEbo()));
//准备测试数据
SaleModel saleModel = new SaleModel();
saleModel.setGoods("moto 手机");
saleModel.setSaleNum(2);
//调用业务功能
ebi.sale("张三","张三丰",saleModel);
ebi.sale("李四","张三丰",saleModel);
}
}
运行结果:
在这里插入图片描述
在方法的前后都植入了逻辑,相当于模拟了Aop的功能。
在这里插入图片描述
java源码重点使用的地方
io流
典型的装饰者模式
Spring 中的TransactionAwareCacheDecorator 类
在这里插入图片描述MyBatis 中的一段处理缓存的设计org.apache.ibatis.cache.Cache
在这里插入图片描述装饰者模式总结(深入反复理解)
装饰者模式的优缺点
优点:
- 1、装饰者是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象
扩展功能,即插即用。 - 2、通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。
- 3、装饰者完全遵守开闭原则。
缺点: - 1、会出现更多的代码,更多的类,增加程序复杂性。
- 2、动态装饰时,多层装饰时会更复杂。
和其他模式的相同和不同对比
与适配器模式
装饰者模式 | 适配器模式 | |
---|---|---|
形式 | 是一种非常特别的适配器模式 | 没有层级关系,装饰器模式有层级关系 |
定义 | 装饰者和被装饰者都实现同一个接口,主要目的是为了扩展之后依旧保留OOP 关系 | 适配器和被适配者没有必然的联系,通常是采用继承或代理的形式进行包装 |
关系 | 关系满足is-a 的关系 | 满足has-a 的关系 |
功能 | 注重覆盖、扩展注重 | 兼容、转换 |
设计 | 设计前置考虑 | 后置考虑 |
与组合模式
在这里插入图片描述与策略模式
在这里插入图片描述与模板方法模式
在这里插入图片描述以上截图的地方大部分来自<研磨设计模式>一书。
个人微信公众号:
搜索: 怒放de每一天
不定时推送相关文章,期待和大家一起成长!!
在这里插入图片描述
完
如果帮助到您,转发请备注出处和谢谢。
网友评论