第一节
前言
各位好,首先我要先恭喜下自己粉丝即将破百,也谢谢各位的捧场,不过也跟我自己的努力密不可分,我也要继续加油,输出更好的文章来回报大家,也希望大家多提建议,有问题我也会及时改进。争取早日跟上各位大佬的步伐。
今天讲解的是创建型设计模式第三篇—装饰者模式(也叫修饰者模式),同样我们通过模式的名字去看实现过程,所谓装饰,就是在本体原有功能的基础上加上修饰,但不能更改原有本体的结构,使得原本的类在原有的结构不变动的基础上增加更多的功能,来拥有更多的功能,这个不修改本体去完成扩展的方式,就叫装饰者模式。
第二节
装饰者模式
装饰者(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。大多情况下,扩展一个类的功能许多人会选择继承的方式。但是继承的耦合度比较高,随着需要扩展功能的增加,子类会变得越来越复杂和臃肿,装饰者模式使用组合关系来创建一个包装对象来包含真实对象(原有对象),并且在原有对象的结构体不变的前提下,增加额外的功能,这个就是装饰者的实现过程。
装饰者模式组成
1
抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象,就是扩展前对象的抽象。
2
具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责,即需要装饰的原有对象本体。
3
抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能,即装饰原有对象的对象的抽象。
4
具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任,具体的装饰者,扩展的功能其实还是具体装饰者做的。
场景举例
我们小区楼下有一个卖鸡蛋灌饼的大妈,他们家每天的生意都很好,需要吃个灌饼都需要排队,一个基础版的灌饼就是灌饼+榨菜+生菜,在灌饼原有基础上老板也推出了套餐A和套餐B和豪华版套餐,A套餐可以加一种食物、B套餐可以加两种食物,豪华版就是三种食物,食物分别是辣条、煎蛋、烤肠,我和我的朋友对食物的喜欢程度不同,我喜欢加烤肠,我的朋友家底比较厚,他喜欢豪华版套餐,但是仔细想想,其实我们吃的都还是个灌饼,但是老板在原有灌饼的基础上进行修饰,抽象出了三个修饰的灌饼套餐版本,具体的套餐内容由每个顾客决定,这个不修改本体但又给本体扩展的过程,使用的就是修饰者模式。
UML图
第三节
代码实现
1.创建抽象构建“灌饼”类
package com.yang.decorator;/** * @ClassName AbstractComponent * @Description 抽象构建角色灌饼 * @Author IT小白架构师之路 * @Date 2020/12/20 20:44 * @Version 1.0 **/publicinterfaceAbstractPancake{/** * 灌饼可以吃 */publicvoideat();}
2.创建具体构件角色“鸡蛋灌饼类”
package com.yang.decorator;/** * @ClassName EggPancake * @Description 具体构件角色-鸡蛋灌饼 * @Author IT小白架构师之路 * @Date 2020/12/20 20:48 * @Version 1.0 **/publicclassEggPancakeimplementsAbstractPancake{@Overridepublicvoideat(){ System.out.println("鸡蛋灌饼本来有生菜、榨菜"); }}
3.创建装饰抽象角色类
package com.yang.decorator;/** * @ClassName DecoratorPancake * @Description 装饰抽象角色 装饰的鸡蛋灌饼的抽象 * @Author IT小白架构师之路 * @Date 2020/12/20 20:50 * @Version 1.0 **/publicclassDecoratorPancakeimplementsAbstractPancake{//成员对象引入具体构件角色,就是要修饰的对象private AbstractPancake abstractPancake;//构造赋值具体构件publicDecoratorPancake(AbstractPancake abstractPancake){this.abstractPancake = abstractPancake; }@Overridepublicvoideat(){ abstractPancake.eat(); }}
4.创建具体装饰角色A和B“灌饼套餐A和B”
package com.yang.decorator;/** * @ClassName ConcreteDecoratorPakageOne * @Description 具体装饰者A套餐 * @Author IT小白架构师之路 * @Date 2020/12/20 20:53 * @Version 1.0 **/publicclassConcreteDecoratorAextendsDecoratorPancake{publicConcreteDecoratorA(AbstractPancake abstractPancake){super(abstractPancake); }@Overridepublicvoideat(){ addOne();super.eat(); }/** * 加一种吃的 */publicvoidaddOne(){ System.out.println("给鸡蛋灌饼增加了烤肠"); }}package com.yang.decorator;/** * @ClassName ConcreteDecoratorB * @Description 具体装饰者B套餐 * @Author IT小白架构师之路 * @Date 2020/12/20 20:57 * @Version 1.0 **/publicclassConcreteDecoratorBextendsDecoratorPancake{publicConcreteDecoratorB(AbstractPancake abstractPancake){super(abstractPancake); }@Overridepublicvoideat(){ addTwo();super.eat(); }publicvoidaddTwo(){ System.out.println("灌饼增加了烤肠、辣条"); }}
5.创建客户端进行测试
package com.yang.decorator;/** * @ClassName Client * @Description 客户端 * @Author IT小白架构师之路 * @Date 2020/12/20 20:59 * @Version 1.0 **/publicclassClient{publicstaticvoidmain(String[] args){//生成具体构件 AbstractPancake abstractPancake = new EggPancake();//生成具体扩展构件A套餐 DecoratorPancake decoratorPancake = new ConcreteDecoratorA(abstractPancake);//调用原有的基础方法 decoratorPancake.eat(); System.out.println("-------------我是分割线------------------");//生成具体扩展构件B套餐 decoratorPancake = new ConcreteDecoratorB(abstractPancake); decoratorPancake.eat(); }}
6.程序运行结果如下,在原有的类结构保持不变的情况下完成装饰,增加更多的功能
给鸡蛋灌饼增加了烤肠鸡蛋灌饼本来有生菜、榨菜-------------我是分割线------------------灌饼增加了烤肠、辣条鸡蛋灌饼本来有生菜、榨菜
第四节
装饰者模式的优缺点及适用场景
优点:
1.在原有对象结构不变的情况下完成功能扩展,比较灵活。
2.装饰类可以增加多个,使用不同的装饰类可以完成不同的功能扩展。
3.具体构件类与具体装饰类可以独立变化,可以根据需要增加新的具体构件和具体装饰类,原类库不需要改变。
缺点:
1.使用装饰者模式,当需要的装饰场景较多时,会产生大量的具体装饰类,会增加系统资源占用,可能会影响程序性能。
2.使用装饰模式虽然比继承更灵活,但是当对象被多次修饰时,当程序运行过程中出现问题,排错过程会变得更加复杂。
适用场景:
1.需要在不影响原有对象的情况下,动态、透明的给原有对象扩展功能内容场景时。
2.不能采用继承的方式对原有对象进行扩展时,可以使用装饰模式。