设计模式----装饰者模式详解及应用

装饰者模式(开闭原则)-Decorator

在这里插入图片描述

定义:不改变原有对象的情况下,给一个对象扩展功能
应用:
  • JAVA I/O中的装饰者模式
  • spring session中的装饰者模式
  • Mybatis缓存中的装饰者模式
JAVA I/O中的装饰者模式

抽象构件:Component(抽象类)-------------相当于I/O流里面InputStream/OutputStream和Reader/Writer
具体构件:ConcreteComponent()-------相当于I/O里面的FileOutputStream和FileInputStream。
装饰角色:Decorator()---------------------相当于I/O流里面的FilterOutputStream过滤流类
具体装饰:ConcreteDecorator(对象)------相当于I/O流里面的BufferedOutputStream缓冲流类等

流名称(省略inputStream)应用场景装饰者中扮演的角色
ByteArray访问数组,把内存中的一个缓冲区作为 InputStream 使用,CPU从缓存区读取数据比从存储介质的速率快10倍以上具体构件
StringBuffer把一个 String 对象作为。InputStream。不建议使用,在转换字符的问题上有缺陷具体构件
File访问文件,把一个文件作为 InputStream ,实现对文件的读取操作具体构件
Piped访问管道,主要在线程中使用,一个线程通过管道输出流发送数据,而另一个线程通过管道输入流读取数据,这样可实现两个线程间的通讯具体构件
Sequence把多个 InputStream 合并为一个 InputStream . “序列输入流”类允许应用程序把几个输入流连续地合并起来具体构件
Data特殊流,读各种基本类型数据,如byte、int、String的功能具体装饰
Object对象流,读对象的功能具体构件
PushBack推回输入流,可以把读取进来的某些数据重新回退到输入流的缓冲区之中具体装饰
Buffered缓冲流,增加了缓冲功能具体装饰
LineNumber额外的功能是它增加了目标文件中的行号具体装饰

全部I/O流(具体的i/o流章节细讲)

img

大致是:

1.我要对字节,字符流进行装饰。

2.我要对具体的文件形式的字节字符流进行装饰。

3.我要让过滤流类作为**装饰(抽象)**来去对具体指定对象进行装饰

(看出来程序员不管搞什么都很细节),像我这个菜鸡写代码就想不到直接装饰设成抽象,一定是具体装饰写了巨多种情况后,才会想到用抽象装饰去封装一波。

4.我要让缓冲流类等等作为具体装饰来对具体指定对象进行装饰

JAVA I/O实例代码:

BufferedReader xxx = new BufferedReader(new InputStreamReader(new DeflaterInputStream(new DataInputStream(new FileInputStream(new File("xxx"))))));
// 抽象的来说就是可以给想要装饰的角色一直套娃

而I/O流的抽象装饰之所以存在的意义还是因为多种具体装饰肯定会有共同的方法,所以在Reader和BufferedReader这种具体装饰之间才需要抽象装饰来实现相同方法来简化,然而BufferedReader字符流压根没有与其他类有相同的方法,或者说有相同的方法在Reader这个抽象类里了,所以压根不需要继承FilterReader,而BufferInputStream则不一样,可能有很多具体的装饰与其有相同方法,所以要经过一个FilterInputStream。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

有意思的是:由上面几张图可以看到,它们都调用了它们父类的构造,来完成初始化,Filter是包私有的,所以就算它是普通类,你在idea里可以拿到,但是用不了,如果你不了解里面的构造原理,压根不知道为什么这个类我能拿到,却用不了,而且Reader和InputStream也不是接口,所以我觉着这里IO流用装扮者模式很牵强,扩展功能的时候为什么不用接口去搞啊,为什么非要实现一个Filter来专门实现一个装饰者,,为以后的功能进行扩展,我暂时的理解是因为虽然同样是扩展功能,但是功能与功能之间又不是相互独立的而是互相参杂的,导致功能扩展不好用接口,而用装扮者来拓展功能更合适一点,我暂时也想不到其他好的模式。

需要注意的是:是装饰者和被装饰者必须达到类型匹配,这样他们才能组合在一起,然后共同去描述和修饰某一事物。

还有一个值得注意的点:

BufferedReader初始化时,默认缓冲区大小是8192字符数组,而BufferedInputStream初始化时,默认缓冲区大小是8192字节数组,也就是一个16k,一个8k,需要分清楚。

JAVA mybatis中 二级缓存的装饰者模式

mybatis的装饰者直接放在了/ibatis/cache/decorators,(很明显)

在这里插入图片描述

查看它的UML图,刚开始说它是装饰者我是有点不信的,后来仔细看是把装饰者简化了

在这里插入图片描述

仔细看一下它的目录结构,其他的都作为装饰器放在了decorators,而PerpetualCache作为接口的实现工具类放在了impl包下。所以它作为具体构件即被装饰者,而其他都是装饰者。

mybatis对装饰者模式进行了简化但是核心仍在
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

也就是实现装饰者的核心一定要保证装饰者和被装饰者的类型一致,所以装饰者初始化时一定传入的时大家所共有的接口或抽象类(超类),来保证我保存上一个被装饰者的功能和传给下一个装饰者时的功能的一个完整适配。

缓存类型作用角色
FifoCache先进先出算法,缓存回收策略装饰者
LoggingCache输出缓存命中的日志信息装饰者
LruCache最近最少使用算法,缓存回收策略装饰者
ScheduledCache调度缓存,负责定时清空缓存装饰者
SerializedCache缓存序列化和反序列化存储装饰者
SoftCache基于软引用实现的缓存管理策略装饰者
SynchronizedCache同步的缓存装饰器,用于防止多线程并发访问装饰者
WeakCache基于弱引用实现的缓存管理策略装饰者
TransactionalCache事务缓存 , 一次性存入或移除多个缓存装饰者
PerpetualCache(一级)永久缓存 ,一旦存入就一直保持被装饰者
  • 一级缓存,又叫本地缓存,是PerpetualCache类型的永久缓存,保存在执行器中
    (BaseExecutor),而执行器又在SqlSession(DefaultSqlSession)中,所以
    一级缓存的生命周期与SqlSession是相同的。
  • 二级缓存,又叫自定义缓存,实现了Cache接口的类都可以作为二级缓存,所以可配置如encache等的第三方缓存。二级缓存以namespace名称空间为其唯一标识,被保存在Configuration核心配置对象中
总结:
优点:
  1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
  2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合
缺点:
1.这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值