运行时的扩展远比编译时的继承威力大?
继承威力强大,但是他并不总是能实现有足够弹性和最好维护的设计。
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。
然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态进行扩展。利用这个技巧把多个新职责,甚至是在设计超类时还没有想到的职责加在对象上。而且可以不用修改原来的代码。
通过动态的组合对象,可以写新的代码添加新功能,而不需要修改现有代码。既然没有改变现有代码,那么引进bug或产生意外副作用的机会将大幅度减少。
类应该对扩展开放,对修改关闭: 在不修改现有代码的情况下,就可以搭配新的行为。
如何让设计的每个部分都遵循开放-关闭原则?
答:通常,办不到。要让OO设计同时具备开放性和关闭性,有不修改现有的代码,需要花费大量的时间和努力。一般来说我们没有这么多的时间和精力做的各个部分都是这么设计。
遵循开放-关闭原则,通常会引入新的抽象层侧,增加代码的复杂度。所以关注设计中有可能改变的地方,然后应用开放、关闭原则。
定义:动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
学会了装饰的技巧, 能够在不修改任何底层代码的情况下,给对象赋予新的职责。
装饰者的使用:
java I/O: 但是java I/O也引出了一个装饰者模式的“缺点”:利用装饰者模式,常常造成设计中有大量的小类,数量实在太多,可能会造成使用此API程序员的困扰。但是,了解了装饰者的工作原理,在使用别人的装饰API时,就可以很容易辨别出装饰类的组织过程。
装饰者通常是用工厂模式或者生成器模式创建的
知识点总结
设计原则
- 封装变换
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力
- 对扩展开放,对修改关闭
要点
- 继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式。
- 在我们的设计中,应该允许行为可以被扩展,而无需修改现有的代码
- 组合和委托可用于在运行时动态的加上新的行为。
- 除了继承,装饰者模式也可以让我们扩展行为。
- 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
- 装饰者类反应出被装饰的组件类型(事实上,它们具有相同的类型,都经过接口继承实现)
- 装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
- 你可以用无数个装饰者包装一个组件。
- 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
- 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。