第二课 面向对象设计原则

一. 为什么要面向对象设计

变化是复用的天敌!

面向对象设计最大的优势在于:


抵御变化!


二. 重新认识面向对象

        之前,我们对于面向对象的理解是封装、继承、多态。这三种其实是从底层思维层面的理解,而从抽象思维层面,面向对象应该是:

>> 理解隔离变化

        · 从宏观层面看,面向对象的构建方式更能适应软件的变化,能将变化所带来的影响减为最小;

>> 各司其职

        · 从微观层面看,面向对象的方式更强调各个类的“责任”;

        · 由于需求变化导致的新增类型不应该影响原来类型的实现—所谓各负其责;

        (比如上节课中,画线的责任应该交给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。)

        这一原则与依赖导致原则是相辅相成的,二者违背其一,往往则另一条原则也会违背。

四. 面向接口设计

产业强生的标志


 接口标准化!


>> 接口标准化的意义就是分工协作;

>> 秦国为什么能统一六国?

        秦国有统一的标准,包括剑、戈、弩、箭头等都是一样的,而其他六国则不是。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值