装饰者模式
基本概念
装饰者模式:是一种结构型设计模式,动态地将额外责任附加到对象上。对于拓展功能,装饰者提供了子类化之外的弹性替代方案,提供了比子类化更灵活的拓展方案,允许在运行时动态添加或删除对象的行为。
核心思想是:使用装饰者包装原始对象,装饰者与原始对象实现相同接口,从而在不修改原始对象的前提下,为其添加新功能。
核心结构
Component
(组件):定义对象接口,装饰者和被装饰者都实现此接口ConcreteComponent
(具体组件):接口的具体实现类,即被装饰的原始对象Decorator
(装饰者抽象类):持有组件引用,实现与组件相同的接口ConcreteDecorator
(具体装饰者):实现装饰逻辑,为组件添加新功能
示例说明
场景一:有一家咖啡连锁店,需要设计一个下单系统,其中需要设计一个拓展性强且耦合性低的咖啡设计结构,用户能够选择不同的调料,各种调教价格不一,同时存在后续新增的调料。
- 咖啡基类
1 | // 咖啡基类 |
- 改造咖啡基类,负责咖啡的基本属性,如描述等等,计算价格由饮料子类进行重写,如下:
1 |
|
- 饮料子类对描述进行设置,同时重新重写
cost()
方法。这个时候仍需要一个调料,用户可能选择多个调料,描述,价格也需要计算。新增饮料抽象类(装饰者)如下:
1 | // 首先,我们需要和Beverage类建立继承关系,因此我们拓展Beverage类 |
- 有了这个装饰者抽象类,调料类只需要继承此类即可,如下:
1 | // 摩卡调料 |
- Whip调料
1 |
|
- 测试验证
1 | public static void main(String[] args) { |
首先创建一个咖啡对象(浓缩咖啡),使用Mocha、Whip对象进行包裹,最后可以获得一份带有Mocha、Whip调料到咖啡,这就是装饰者模式。当前更好的创建装饰者对象的方式可以用到工厂和生成器模式。
关于装饰者模式:
- 装饰者和所装饰对象有着相同的超类型;
- 可以用一个或多个装饰者包裹同一个对象;
- 鉴于装饰者有着和所装饰对象相同的超类型,在需要原始对象的情况下,可以传递一个被装饰的对象;
- 装饰者在委托给所装饰对象之前或之后添加自己的行为,来做剩下的工作;
- 对象可以在任何时候被装饰,因此可以在运行时用任意数量的装饰者动态地装饰对象;
类图如下:
总结
优点
- 灵活扩展功能:无需修改原始类,通过组合方式动态添加功能;
- 避免子类爆炸:比继承更高效,减少子类数量;
- 单一职责原则:每个装饰者专注于单一功能,代码更易维护;
- 动态组合:运行时可自由组合多个装饰者,实现复杂功能;
缺点
- 类数量增加:大量装饰者类可能导致代码结构复杂;
- 调试难度:多层装饰可能导致调用链变长,调试更困难;
- 接口一致性:装饰者必须与组件实现相同接口,限制了扩展性;
- 管理难度增加:使用装饰者模式,需要管理更多的对象,可能存在使用的遗漏,因此一般装饰者模式可以用其他模式进行创建,如工厂模式、生成器模式;
使用场景
- Java IO流:典型的装饰者模式应用
InputStream
(组件)、FileInputStream
(具体组件)
FilterInputStream
(装饰者抽象类)
BufferedInputStream
、DataInputStream
(具体装饰者)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Lavigne-yang.Blog!
评论