装饰器模式是JAVA开发过程中常用的一种设计模式,该设计模式用于对类进行横向的功能扩展,也就是达到对类进行“装饰”的目的。JDK中的IO流便是使用了装饰类模式。
装饰器模式的类图一般如下:
以实体类基类的引用为入参,装饰类可以装饰整个继承链上的实体类。
I/O流的继承关系更为直接:
很多刚刚接触装饰模式的开发者可能会认为,为一个类增加一个装饰类多此一举,使用继承也可以对类的功能进行扩展。
但其实装饰模式的核心在于“装饰”,它是一种横向的扩展,并不影响原来类的核心功能和定位。另外通过向上转型传入参数,装饰类可以使用同一个引用并装饰一条继承链中的所有类,具有很好的通用性和可读性。
比如有如下场景,我们有一条继承链:
代码如下:
货车省略。。。
公交车、出租车、货车都是汽车的子类,它们同时拥有 run() 方法且都有自己的实现(都重写了父类的run()方法)。如果我们在后期考虑到,碰到大雾情况,汽车在行驶之前需要开启雾灯。如果不使用装饰模式,我们必须在每个子类的run()方法中加上“开启雾灯”,这样做显然会产生很多重复代码,不够优雅。
现在我们来定义一个装饰器CarDecorator如下:
将一个Car的实例传入装饰器,并执行car的run方法。该类只是一个声明,后续所有的装饰器都会集成自该类。因为我们并不一定只需要开启雾灯的装饰类,我们可能还需要下雨天开启雨刷的装饰类。装饰类应当有自己的继承链,方便其扩展并使其使用更加富有语义。比如我们需要所有的装饰方法都需要一个特定的通用方法,将其放在CarDecorator中显然比放在Car中更加符合语义。
开启雾灯的装饰类如下:
这样,无论我们开那种车,想要开启雾灯则只要获取其装饰实例即可:
执行结果如下:
如果此时我们又下雨又下雾,我们还需要开启雨刷,并且为了安全在开启雾灯与雨刷前都要检查一下设备情况,那么我们只需要为所有装饰类加一个检查车况的通用方法,并新增一个开启雨刷的装饰类即可。
修改后的装饰类基类:
修改后的开启雾灯装饰类:
开启雨刷装饰类:
那么我们在使用时,只需要再多一层包装,便可以开启雨刷: