装饰器模式
为什么需要装饰器模式?
- 实践编程时,新需求总是在软件的整个生命周期中不断出现的。每当有新需求出现时就需要为某些组件添加新的功能来满足这些需求。具体有两种方式:
- 可以直接修改已有组件的代码并添加相应的新功能,很明显这会破坏已有组件的稳定性。而且这种方式显然违反了"开放-封闭"原则。
- 使用继承方式,可以创建子类并在子类中添加新功能实现新需求。但是这种方式会有两种问题产生:
- 有可能有些组件是被final修饰的类
- 如果新需求很复杂,很可能会导致大量子类的出现
- 而装饰器模式就能帮我们解决这种问题,装饰器可以动态地为对象添加功能,它是基于组合的方式实现该功能的。设计模式中有一句常见的话:组合优于继承。
- 装饰器模式有两个明显的优点:
- 相对于继承来讲,装饰器模式的灵活性更强,可扩展性也更强。装饰器模式可以将复杂的功能切分成一个个独立的装饰器,通过多个独立的装饰器的动态组合,创建不同功能的组件,从而满足多种不同需求。
- 当有新功能需要添加时,只需要添加新的装饰器实现类,然后通过组合方式添加这个新装饰器即可,无需修改现有类的代码。
什么是装饰器模式?
- 装饰器模式有多个角色,首先了解这些角色:
- Component(组件),组件接口定义了全部组件实现类以及所有装饰器实现的行为
- ConcreteComponent(具体组件实现类),具体组件实现类实现了Component接口。通常情况下,具体组件实现类就是被装饰器装饰的原始对象,该类提供了Component接口中定义的最基本功能,其他高级功能或后续添加的功能,都是通过装饰器的方法添加到该类的对象之上的。
- Decorator(装饰器),所有装饰器的父类,它是一个实现了Component接口的抽象类,并在其中封装了一个Component对象,也就是被装饰的对象。而这个被装饰的对象只要是Component对象即可,这就实现了装饰器的组合和复用。
- ConcreteDecorator:具体的装饰器实现类,该实现类要向被装饰对象添加某些功能
装饰器模式的典型事例
- 在MyBatis的缓存模块中,就使用了装饰器模式的变体,其中将Decorator接口和Component接口合并成为了一个Component接口。
装饰器模式的缺点
- 随着添加的新需求越来越多,可能会创建出多层装饰器的对象,这增加了系统的复杂性,也增加了理解的难度和定位错误的难度。