无用的设计模式之装饰者模式

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

前言

装饰者设计模式本来是很常用的模式,常用到随处可见,jdk的bio设计都是遵循这个模式的,偶然的机会发现,貌似jdk中bio的装饰者模式和设计模式中的装饰者设计模式却有点本质上的不同,但是仔细想想,貌似bio的设计貌似还有点违背设计模式的本意,此文中把装饰者模式说成无用,是因为他定义的这种规范的玩法,大家貌似并不遵从,反而更喜欢jdk中的用法。


类图

无用的设计模式之装饰者模式


这个类图大家也并不陌生,具体的被装饰的类和装饰者都是遵循同一个规范,component,此处如果component没有公共的定义方法,那就是妥妥的面向接口编程。看这个用法我们也能猜到怎么用,先创建被装饰的类,然后用装饰类去修饰被装饰的类,然后把引用给component,调用operation的时候就把装饰的效果显示出来,如果需求变更,那么直接把装饰组合出来的过程改改,其他代码不需要改变。


jdk bio的用法

作为装饰者模式的典型,他的类图完全和上面的类图吻合,但是我们的用法却大大不同,我们包装后的IO类,我们很少直接让接口来作为引用,每一个装饰类都带了自己的新特性,API都不一样了。我们想要用包装类的功能就必须使用包装类的引用,否则就切面了,我们能用到的只有接口的方法。他的侧重是不同的包装是不同的功能,类似readline,只有bufferedreader有,我们想用只能依靠这个包装类,但是类本身也遵循接口,所以也能传递给接口,但是要损失包装的特性。


两种用法的对比

单纯从软件设计讲,jdk io的设计扩展性不好,因为你选择包装,本来就是希望调用统一的方法,这样对代码的修改最小。但现实是我们如果不用具体的类无法增加新的功能。也就是说你想体现新的功能的话,后面的代码基本要重写。大家公有的那部分方法压根没有增强到,这样写肯定会带来不小的隐患,但很特殊的是,他设计的是IO,一般读取完就over,有传递的可能性,但是用接口传过去后重新包装一下又可以使用了,反正是各自包装各自的,公有的方法都不用,这样下来反而也没什么影响。要选择这么使用的话一定得慎重,用不好就带来很多麻烦。


适合场景

一看类图,大家基本就能感觉这个更像补救型的模式,就是原来的类都实现好了,现在突然要改需求,给里面的部分类的方法都增加一种或者多种功能,这样装饰者模式就派上用场了,直接在建造对象的地方加一段装饰,当然这个前提都是被装饰的类和装饰的类都是可以估计的,遇到不可估计的情况还是直接用aop动态代理吧,不要再考虑装饰模式。既然是补救行的,那么也是有一定要求的。

无用的设计模式之装饰者模式

起码最初的类图是这样的,要不然还要添加接口等等(这个肯定是不可取的),POJO的话还是用动态代理的好。

另外一种适合情况就是多继承,要对中间继承类需要增加,这种情况用装饰者模式不会影响子类的功能。


和静态代理的区别

其实文中多次提到代理,其实在功能单一的情况下,代理和装饰都可以,我最后想想还是从功能上做点区别,装饰者适合新增的功能可以互相组合的情况,及装饰类和装饰类是可以叠加操作的,并且被装饰的方法还是较少的,装饰的类的个数也是较少的。静态代理更适合类中方法很多,但是只会代理一层,出现多层代理基本就是不合理的,典型的就是datasource中用自己的connection类代理jdbc中的connection类。


最后说几句

其实用装饰者模式带来种种功能上的好处,但是一旦出现问题,你自己写的代码还好,要是让纯粹不知道的人走断点找问题,那跟断点可就费事了,所以一定留好设计文档和把类的名字起的见字生义。


原文始发于微信公众号(一次编译多处运行):无用的设计模式之装饰者模式