设计模式第7讲——装饰者模式(Decorator)
装饰者模式是一种结构型设计模式。一、什么是装饰者模式 二、角色组成 三、优缺点 四、应用场景 4.1 应用实例 4.2 java实例 五、代码实现5.0 UML类图5.1 Hero(英雄-抽象组件)5.2 BlindMonk(盲僧-具体构件)5.3 SkillDecorator(技能装饰-抽象装饰器)5.4 QDecorator(Q技能-具体装饰器)5.5 WDecorator(W技能-具体装饰器
·
一、什么是装饰者模式
装饰者模式是一种结构型设计模式,它允许你动态地向对象添加新的行为而不影响其原有的行为。它在运行时给对象动态地添加一些额外的职责,通常是在原有的行为基础上,通过装饰器进行一些修饰,实现了更加灵活的代码复用和扩充。
二、角色组成
- 抽象构件(Component):要求装饰者对象都实现一个抽象接口或抽象类。(接口或抽象类)
- 具体构件(ConcreteComponent):定义了一个具体的对象,也就是需要被装饰的对象。
- 抽象装饰器(Decorator):持有一个真实的构建对象的引用,并且可以动态给该对象添加新的功能。(接口或抽象类)
- 具体装饰器(ConcreteDecorator):实现具体的装饰器,向真实的构建对象添加新功能。
三、优缺点
优点:
- 非常灵活且可扩展,能动态地为对象添加新的职责和行为。
- 遵循开闭原则,能够实现代码的可维护性和可扩展性。
- 通过使用装饰器对象,可以避免不必要的继承以及子类的数量爆炸性增长问题。
缺点:
- 会导致系统变得复杂,增加了许多类和对象的相互关系,需要开发人员具备更高的抽象能力和设计能力。
- 增加了代码复杂度,使得项目开发和维护更加困难。
四、应用场景
4.1 生活场景
- 穿衣服:我们每天都要穿衣服,根据不同的场合和气温选择不同的服装,比如外套、围巾、帽子等,这些都是具体装饰器(Concrete Decorator),而我们就是被装饰的抽象组件(Component)。
- 手机配件:如手机壳、钢化膜等。都可以看作是装饰者模式的应用,手机就是抽象组件(Component),手机壳、钢化膜等都是具体装饰器(Concrete Decorator)。
- 电影特效:如烟雾、爆炸、光影等,影片为抽象组件(Component),各种特效就是具体装饰器(Concrete Decorator)。
4.2 java场景
- IO流的处理:这是一个典型的装饰者模式的应用。InputSteam和OutputStream是最基本的抽象组件(Component),而各种FilterInputSteam和FilterOutputStream就是具体的装饰器,它们可以实现各种不同的IO流处理功能,如缓冲、压缩、加密等等。
- 数据库连接池:连接池为抽象组件(Component),各种不同的连接池实现(如C3P0、DBCP等)则是具体的装饰器(Concrete Decorator),它们可以实现不同的连接池缓存策略、连接池大小、超时时间等属性。
- Spring的AOP:在AOP中,切面就是具体的装饰器(Concrete Decorator),而业务逻辑则是抽象组件(Component),通过动态代理技术,将具体的业务逻辑和切面对象组合起来,我们就可以实现在不修改源码的情况下,动态地为业务逻辑添加新的功能。
五、代码实现
下面以英雄联盟中李青(盲僧)学技能为例。其中Hero代表英雄(抽象构件)、BlindMonk(盲僧-具体构件)、SkillDecorator(技能-抽象装饰器)、QWERDecorator为英雄的四个技能(具体装饰器)
5.0 UML类图
5.1 Hero(英雄-抽象组件)
/**
* @author Created by njy on 2023/6/6
* 英雄
*/
public interface Hero {
/**
* 学技能
*/
void learnSkill();
}
5.2 BlindMonk(盲僧-具体构件)
import lombok.Data;
/**
* @author Created by njy on 2023/6/6
* 盲僧
*/
@Data
public class BlindMonk implements Hero{
private String name;
public BlindMonk(String name){
this.name=name;
}
@Override
public void learnSkill() {
System.out.println(getName());
}
}
5.3 SkillDecorator(技能装饰-抽象装饰器)
/**
* @author Created by njy on 2023/6/6
* 学技能(装饰hero)
*/
public interface SkillDecorator extends Hero{
void learnSkill();
}
5.4 QDecorator(Q技能-具体装饰器)
/**
* @author Created by njy on 2023/6/6
* Q技能
*/
public class QDecorator implements SkillDecorator{
private Hero hero;
private String name;
public QDecorator(Hero hero,String name){
this.name=name;
this.hero=hero;
}
private void learnQ(){
System.out.println("习得技能"+name);
}
@Override
public void learnSkill() {
hero.learnSkill();
learnQ();
}
}
5.5 WDecorator(W技能-具体装饰器)
/**
* @author Created by njy on 2023/6/6
* W技能
*/
public class WDecorator implements SkillDecorator{
private Hero hero;
private String name;
public WDecorator(Hero hero,String name){
this.name=name;
this.hero=hero;
}
private void learnW(){
System.out.println("习得技能"+name);
}
@Override
public void learnSkill() {
hero.learnSkill();
learnW();
}
}
5.6 EDecorator(E技能-具体装饰器)
/**
* @author Created by njy on 2023/6/6
* E技能
*/
public class EDecorator implements SkillDecorator{
private Hero hero;
private String name;
public EDecorator(Hero hero,String name){
this.name=name;
this.hero=hero;
}
private void learnE(){
System.out.println("习得技能"+name);
}
@Override
public void learnSkill() {
hero.learnSkill();
learnE();
}
}
5.7 RDecorator(R技能-具体装饰器)
/**
* @author Created by njy on 2023/6/6
* R技能
*/
public class RDecorator implements SkillDecorator{
private Hero hero;
private String name;
public RDecorator(Hero hero,String name){
this.name=name;
this.hero=hero;
}
private void learnR(){
System.out.println("习得技能"+name);
}
@Override
public void learnSkill() {
hero.learnSkill();
learnR();
}
}
5.8 TestDecorator
/**
* @author Created by njy on 2023/6/5
*/
@SpringBootTest
public class TestDecoration {
@Test
void testDecoration(){
QDecorator q=new QDecorator(new BlindMonk("李青"),"Q:天音波/回音击");
WDecorator w=new WDecorator(q,"W:金钟罩/铁布衫");
EDecorator e=new EDecorator(w,"E:天雷破/摧筋断骨");
RDecorator r=new RDecorator(e,"R:猛龙摆尾");
r.learnSkill();
}
}
六、总结
- 给对象添加一些职责,但是又不想改变其原有的接口和实现。
- 需要对不同组合的对象进行扩展,从而避免出现由于继承关系带来的类很多问题。
- 在不使用继承的情况下动态地为一个对象添加一些额外的功能。
- 需要在程序运行时动态地为对象添加不同的功能,或者为对象添加同时使用多个的功能。
一句话,当遇到需要给某个类添加新功能,但又不能改源代码或不希望影响其他对象的情况下,可以考虑装饰者模式。
END:更多设计模式的介绍,推荐移步至👉 23种设计模式学习导航(Java完整版)👈
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献3条内容
所有评论(0)