前言
上一篇文章中,分享了适配器模式的一些相关知识,在本篇文章将为大家分享装饰器模式,乍一听,适配器和装饰器,是不是有点类似的感觉?其实这两种模式,完全是两种不同的设计模式,下面就开始正题吧,如果我的分享内容对你有用,请关注我的微信公众号吧,后续会持续输出更多的干货内容的哦!
什么是装饰器模式
装饰器模式是一种结构型设计模式,它允许向一个现有的对象动态添加功能,而不需要修改其源代码。这种模式的核心思想是使用装饰器类来包装原始类,并在保持类方法签名完整性的前提下,提供额外的功能。每个装饰器都包装了原始组件,并添加了新的功能。这些装饰器可以被嵌套,以实现更多的功能组合。使用装饰器模式的好处之一是在运行时动态添加或删除功能,而不会对原始组件的代码产生影响。这种灵活性使得装饰器模式非常适用于大型项目中的代码重构和维护。
装饰器模式的核心角色
装饰器模式的核心角色包括:
- 抽象组件(Component):这是一个接口或者抽象类,它定义了原始对象的基本行为。装饰器模式要求这个接口或抽象类能够被装饰器类和具体组件类共享。
- 具体组件(Concrete Component):这是被装饰的原始对象,它实现了抽象组件定义的行为。
- 抽象装饰器(Decorator):这是一个继承自抽象组件的类,它持有一个抽象组件对象,并定义了与抽象组件相同的接口。抽象装饰器类通过组合方式持有其他装饰器对象,它可以向抽象组件添加新的功能。
- 具体装饰器(Concrete Decorator):这是实现了抽象装饰器的类,它负责向抽象组件添加新的功能。通常,具体装饰器会在调用原始对象的方法之前或之后执行自己的操作。
这些核心角色共同实现了装饰器模式的主要功能,即在保持原始对象行为不变的同时,动态地添加新的功能。
在Java中,适配器模式如何实现?
假如在做一个管理飞机的程序,要展示飞机的特性,应该怎么设计这个程序呢?如果使用装饰器模式,是这样的:
/*** 抽象组件:飞机*/
public abstract class Aircraft {public String type;public Aircraft(String type) {this.type = type;}abstract void show();}
public class OrdinaryAircraft extends Aircraft {public OrdinaryAircraft(String type) {super(type);}@Overridepublic void show() {System.out.println("型号:"+super.type);System.out.println("基础特性:飞行");}
}
如果是战斗机呢,除了飞行外,还要具备在空中战斗的能力,当然具备空中战斗能力的飞机种类有很多,比如歼击机、轰炸机、预警机、直升机等,而且后续还有新的型号补发明出来,这就要求程序在设计的时候要有足够的扩展性,使用装饰器模式很简单:
1、定义一个抽象飞机类;
2、定义一个抽象的战斗机,持有抽象飞机类;
3、普通飞机类继承了抽象飞机类,就具备了飞机的基础特性,战斗机最基础的特性也必须能飞行,所以持有一个抽象飞机类,除了战斗机本身的一些特性外,也就拥有了普通飞机的飞行的特性;
4、J15A、J20、WZ10等种型号的飞机继承了抽象战斗机类,就同时拥有了飞行的特性和战斗的特性;当然不同的战斗机的战斗特性不相同,这就是具体的战斗机类中实现就行了;
5、后续再新增其他型号的战斗机,就新增具体的战斗机类并继承抽象战斗机类,完全符合开闭原则;
public abstract class Fighter {protected Aircraft aircraft;public Fighter(Aircraft aircraft) {this.aircraft = aircraft;}abstract void show();
}
/*** 战斗机:歼20*/
public class J20 extends Fighter {public J20(Aircraft aircraft) {super(aircraft);}@Overridepublic void show() {super.aircraft.show();System.out.println("优势特性:空中格斗专家");}
}
/*** 歼15A型战机*/
public class J15A extends Fighter{public J15A(Aircraft aircraft) {super(aircraft);}@Overridevoid show() {super.aircraft.show();System.out.println("优势特性:短距起飞/低空突防");}
}
/*** 武直10武装直升机*/
public class WZ10 extends Fighter{public WZ10(Aircraft aircraft) {super(aircraft);}@Overridevoid show() {super.aircraft.show();System.out.println("优势特性:树梢杀手");}
}
/*** 装饰器模式*/
public class Test7 {public static void main(String[] args) {Aircraft ordinaryAircraft = new OrdinaryAircraft("普通飞机");ordinaryAircraft.show();System.out.println("---------------");Fighter j20 = new J20(new OrdinaryAircraft("歼20战机"));j20.show();System.out.println("---------------");Fighter j15A=new J15A(new OrdinaryAircraft("歼15A型战机")) ;j15A.show();System.out.println("---------------");Fighter wz10=new WZ10(new OrdinaryAircraft("武直10武装直升机"));wz10.show();}
}
装饰器在Spring中的应用
装饰器模式在Spring中有很多应用,主要可以用来动态地给一个对象增加一些额外的职责,即动态地给一个对象穿上衣服。
- 装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。在Spring中,这种特性被广泛应用,例如在Spring Session中,使用装饰器模式对原生的HttpSession进行增强,可以将在分布式session中同步session数据的需求通过扩展其功能的方式“装饰”在原有的HttpSession对象上。
- 另一个应用是在处理HTTP请求时,Spring Session框架使用HTTP请求包装类(如SessionRepositoryRequestWrapper)和Session存储过滤器(如SessionRepositoryFilter)实现。这种方式使用了装饰器模式,以在请求前后加入特定的行为,达到在运行时动态使用、撤销功能的效果。
装饰器的应用场景
装饰器模式在很多场景中都有应用,比如:
- 用于扩展类的功能,可以动态地给对象添加或撤销功能,比如日志记录、缓存处理等。
- 在软件系统中,可以通过装饰器模式方便地为各个类或方法添加日志记录功能,而不需要修改原有的代码。
- 应用于需要进行缓存处理的场景,可以在方法调用时检查缓存是否存在计算结果,如果存在则直接返回,否则进行计算并将结果存入缓存,以提高系统的响应速度。
总结
优点:
- 动态扩展功能:装饰器模式可以在运行时动态地给对象添加或删除功能,而不需要修改原有的代码。
- 灵活性和可扩展性:装饰器模式可以灵活地组合和扩展类的功能,可以根据需要添加或删除装饰器,从而改变对象的行为。
- 代码的可读性和可维护性:装饰器模式可以将多个装饰器组合在一起,形成一个复杂的对象行为,使得代码更加清晰、可读性更好,同时也可以方便地维护和修改代码。
缺点:
- 实现复杂度较高:装饰器模式需要在原有的类上添加一个接口,并在接口中定义了和原有类相同的方法,同时还需要实现一个装饰器类来扩展原有类的功能,这使得代码实现起来较为复杂。
- 可能会引入过多的装饰器类:装饰器模式可以灵活地扩展类的功能,但是也可能会引入过多的装饰器类,使得代码变得冗余和复杂。
- 可能会影响性能:装饰器模式需要在运行时动态地创建对象和调用方法,这可能会影响系统的性能。
总的来说,装饰器模式是一种灵活的设计模式,可以方便地扩展类的功能,但是也需要注意实现复杂度和性能问题。