一. 为什么要面向对象设计
变化是复用的天敌!
面向对象设计最大的优势在于:
抵御变化!
二. 重新认识面向对象
之前,我们对于面向对象的理解是封装、继承、多态。这三种其实是从底层思维层面的理解,而从抽象思维层面,面向对象应该是:
>> 理解隔离变化
· 从宏观层面看,面向对象的构建方式更能适应软件的变化,能将变化所带来的影响减为最小;
>> 各司其职
· 从微观层面看,面向对象的方式更强调各个类的“责任”;
· 由于需求变化导致的新增类型不应该影响原来类型的实现—所谓各负其责;
(比如上节课中,画线的责任应该交给MainForm,还是应该由各个图形实现自己的Draw?)
>> 对象是什么?
· 从语言实现层面来看,对象封装了代码和数据;
· 从规格层面讲,对象是一系列可被使用的公共接口;
· 从概念层面讲,对象是某种拥有责任的抽象;
三. 面向对象设计原则
八大设计原要比具体的某一模式更重要,有些模式在当今的体系下已经不再流行或适用,而设计原则可能会帮助你发明新的设计模式。
1. 依赖倒置原则(DIP)
该原则几乎贯穿所有的设计模式,是检验代码设计质量的一个重要标准。
>> 高层模块(稳定)不应该依赖于低层模块(变化),二者应该依赖于抽象(稳定);
(比如上节课的分解思想中,MainForm(高层)依赖Line(低层)和Rect(低层),而抽象思想中,MainForm(高层)依赖的是Shape(抽象),具体的实现(低层)也依赖于Shape(抽象),使结构变得稳定。)
>> 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定);
2. 开闭原则(OCP)
>> 对扩展开放,对更改关闭;
>> 类模块应该是可扩展的,但是不可修改;
思考:有一个学校,指定一家木材加工厂生产桌椅板凳,在生产过程中,接到消防通知,需要这些桌椅板凳具备防火的条件,这是最初的需求里没有的。若你是加工厂,会怎么做?
第一种方式:重新按需求生产满足规格的桌椅板凳,原来已生产的砍掉;
第二种方式:在已经生产的桌椅板凳上,刷一层防火涂料。
可以看出,第二种方式更加的明智,面对需求变更时,对已有的方案进行扩展即可,而第一种方法则是整体的更改。我们往往在代码开发过程中,不经意间就做了第一种方式的行为。
回头可以再看一下第一篇文章中的分解和抽象,看看哪些是扩展,哪些是更改(所谓的更改,是指需要重新编译/重新测试/重新部署)
3. 单一职责原则(SRP)
>> 一个类应该仅有一个引起它变化的原因;
>> 变化的方向隐含着类的责任;
比如当一个类特别臃肿的时候,就要考虑是否是类的责任过多。
4. Liskov替换原则(LSP)
>> 子类必须能够替换他们的基类(IS-A);
我如果是你的子类,那么所有用到该父类的地方,子类都应该可以替换并正常使用。很多人认为这是天经地义的事,但在开发中,就会有这样的情况出现:子类继承了父类,却不可以使用父类的某些方法,当用到这些方法时,就用抛异常的方式解决,这就明显违背了该原则。
如果子类不能使用父类的某些方法,很可能该子类就不应该继承那个父类,或者他们之间是一种组合的关系,而非继承。
>> 继承表达类型抽象;
5. 接口隔离原则(ISP)
>> 不应该强迫客户程序依赖他们不用的方法;
>> 接口应该小而完备;
所谓小,就是不应该把不必要的方法public出去,如果只是子类应用,则protect;若只是自己使用,则private;仅当非常有必要时,再public。因为一旦public,会导致调用方与该接口产生依赖,依赖就需要接口的稳定。
6. 优先使用对象组合,而不是类继承
>> 类继承通常为“白箱复用”,对象组合通常为“黑箱复用”;
>> 继承在某种程度上破坏了封装性,子类父类耦合度高;
>> 对象组合只要求被组合的对象具有良好的接口,耦合度低;
类继承曾一度非常被人推崇,觉得继承才是面向对象的正宗门派,这个感觉是错误的。导致这个想法很可能与我们的环境有关,我们人类也是通过父子方式代代相传,所以可能会对继承有莫名的好感。
7. 封装变化点
>> 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良影响,从而实现层次间的松耦合。
封装的初级理解是封装数据和方法,封装的更高层次理解是封装变化点。
8. 针对接口编程,而不是针对实现编程
>> 不将变量类型声明为某个特定的具体类,而是声明为某个接口(该条不要绝对化);
>> 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口;
>> 减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案;
(比如第一课分解思想中的MainForm,它依赖了具体的Line和Rect,而在抽象思想中,则依赖的是接口Shape。)
这一原则与依赖导致原则是相辅相成的,二者违背其一,往往则另一条原则也会违背。
四. 面向接口设计
产业强生的标志
接口标准化!
>> 接口标准化的意义就是分工协作;
>> 秦国为什么能统一六国?
秦国有统一的标准,包括剑、戈、弩、箭头等都是一样的,而其他六国则不是。