敏捷软件开发 第十章、第十一章、第十二章

第10章 Liskov 替换原则(LSP)

原则解释:

子类型(sbutype)必须能够替换掉它们的基类型(base type)

这一章没大看懂,貌似和 OCP(开发关闭原则)关系很大,以后再研究

第11章 依赖倒置原则(DIP)

原则解释:

a. 高层模块不应该依赖于低层模块。二者都应该依赖于抽象。

b. 抽象不应该依赖于细节。细节应该依赖于抽象。

“请注意这个规则里的倒置不仅仅是依赖关系的倒置,它也是接口所有权的倒置。我们通常会认为工具库应该拥有它们自己的接口。但是当应用了 DIP 时,我们发现往往是客户拥有抽象接口,而它们的服务者则从这些抽象接口派生。”

这里谈下我自己对这段话的理解:

由于在平常的开发中,我接触到的以及我自己使用的方式都是,将接口和对应实体类的名字起的相似(后者在前者的名字后加上 impl),所以自然而然地就会认为它们俩是一体的,即“工具库拥有它们自己的接口”

而仔细想一下的话,会发现,其实被调用方存在的意义是:调用方有相关的需求,即调用方需要一些东西,然后说明了自己需要什么样的东西(制定规则),然后被调用方才按照这些规则去做相关的实现。(可以参考实际工作中:正是因为有了需求,技术才有存在的意义)

即,规则的拥有者和制定者从来都是调用方,而不是被调用方

这里可以联想一下 JDBC 相关知识,我们知道,JDBC 自己制定了规范,然后使用 JDBC 操作数据库的用户就可以不必理会数据库具体的实现细节了,他们只需要调用 JDBC 规定好的那些接口就行了(屏蔽了实现细节)

而在 Java 和 数据库厂商 之间,谁拥有主动权?

是 Java

由于 Java 良好的特性,Java 的市场非常的广泛,并且在未来的使用规模也非常可期

由于这一点,和 Java 合作的话,会获取到非常大的市场空间

所以,从商业角度来说,数据库厂商看到这一趋势之后,必定会迎合 Java 的规范

这时,拥有了话语权的 Java(可以看做甲方) 必定会站在自己的角度,制定一套规范,让使用 Java 的开发人员只需要面对这个规范操作数据库(因为在无需关注数据库相关实现细节的情况下,开发人员会省去很多精力,这样一来,Java 受到更多的开发人员欢迎)

在这个例子中,Java 可以被认为是调用方,数据库可以被认为是被调用方,JDBC 规范可以被认为是抽象接口

很显然,JDBC 不是数据库对外暴露的接口规范,而是 Java 作为调用方站在自己的角度,制定的一套规范

理解了接口所有权的归属问题之后,就能理解这个原则的名字为什么叫“依赖倒置”了

画图说明

一般的面向过程编程中,高层对低层的依赖关系如下:

A 所在模块被称为高层模块,B 所在模块被称为低层模块,则在此关系中,高层模块直接依赖于低层模块

当使用接口作为中间人时,如果这么理解

认为接口(b)所有权归被调用方(B)所有

则依赖关系如下图:

即,还是 A 所在的高层模块在依赖 B 所在的低层模块,并没有发生所谓的依赖“倒置”

但是,但我们换一个理解方式,即

认为接口(b)所有权归调用方(A)所有

则依赖关系如下图:

显然,这样理解的话,可以很明显的看出,依赖关系被“倒置”了,因为在此图中,A 所在的模块被 B 所在的模块所依赖

更高阶的操作(或者说更高阶的理解)

即,接口没有所有者,它自己独立于被调用方和调用方,成为了第三个模块

具体可见可见书中 11.3 小节最后几段的叙述

回到上述我画的几个图中,由于 b 和 B 的关系互为大小写,所以会对这种理解造成阻碍,所以,把 b 换成另外一个名字,再重新画一张依赖图:

是否可以按照这个思路理解 Spring 的 IOC 容器呢?即,按照那个流传的说法:调用方和被调用方解耦,它们都依赖于第三方容器

看完这一章的内容,才大概明白一直被吹捧的 Spring 牛在哪里,以及为什么 IOC 是 Spring 的核心之一

同时,结合 Spring,也能更理解书中的一些描述:

“如果高层模块独立于底层模块,那么高层模块就可以非常容易地被重用。该原则(指依赖倒置原则)是框架设计的核心原则”

“使用传统的过程化的程序设计所创建出来的依赖关系结构,策略是依赖于细节的。这是糟糕的,因为这样会使策略收到细节改变的影响。面向对象的程序设计倒置了依赖关系结构,使得细节和策略都依赖于抽象,并且常常是客户拥有服务接口”

“事实上,这种依赖关系的倒置正是好的面向对象设计的标志所在。使用何种语言来编写程序是无关紧要的。如果程序的依赖关系是倒置的,它就是面向对象的设计。如果程序的依赖关系不是倒置的,它就是过程化的设计”

“依赖倒置原则是实现许多面向对象技术所宣称的好处的基本低层机制。它的正确应用对于创建可重用的框架来说是必须的。同时它对于构建在变化面前富有弹性的代码也是非常重要的。由于抽象和细节被彼此隔离,所以代码也非常容易维护。”

个人感悟:

关于经典的原则和设计思想,如果想要深入理解的话,最好直接找到对应的经典书籍查看,而不是在网上找一堆博客看,一来很多博主自己都没有理解清楚,二来,就算博主理解清楚了,也不一定有与那些能写出经典书籍的大师相当的表达能力

如果哪位朋友碰巧看了本文,那么推荐你看看《敏捷软件开发 原则、模式与实践》这本书,书名讲的是敏捷开发,其实里面的内容是面向对象设计的原则和模式,认真看了本书,可以带你进入 OOP 的大门(套用刘大的话,哈哈)。

第12章 接口隔离原则(ISP)

原则解释:

不应该强迫客户依赖于它们不使用的方法

只看了一小部分,大概的理解是:

接口或类中的所有方法,如果可以被更进一步地分组,则应该将它们放置于不同的类或接口中,而不应该笼统地放到同一个类或接口中

原文地址:https://www.cnblogs.com/stone94/p/10591472.html

时间: 2024-10-28 14:49:17

敏捷软件开发 第十章、第十一章、第十二章的相关文章

敏捷软件开发:原则、模式与实践——第10章 LSP:Liskov替换原则

第10章 LSP:Liskov替换原则    Liskov替换原则:子类型(subtype)必须能够替换掉它们的基类型(base type). 10.1 违反LSP的情形 10.1.1 简单例子 对LSP的违反导致了OCP的违反: struct Point { double x, y;} public enum ShapeType { square, circle }; public class Shape { private ShapeType type; public Shape(Shape

敏捷软件开发:原则、模式与实践——第11章 DIP:依赖倒置原则

第11章 DIP:依赖倒置原则 DIP:依赖倒置原则: a.高层模块不应该依赖于低层模块.二者都应该依赖于抽象. b.抽象不应该依赖于细节.细节应该依赖于抽象. 11.1 层次化 下图展示了一个简单的层次化方案: 高层的Policy层使用了低层的Mechanism层,而Mechanism层又使用了更细节的Utility层.它存在一个隐伏的错误特征,那就是:Policy层对于其下一直到Utility层的改动都是敏感的.依赖关系是传递的. 下图展示了一个更为合适的模型: 每个较高层次都为它所需要的服

敏捷软件开发:原则、模式与实践——第5章 重构

第5章 重构 在Martin Fowler的名著<重构>一书中,他把重构定义为:“在不改变代码外在行为的前提下对对代码做出修改,以改进代码内部结构的过程.”可是我们为什么要改进已经能够工作的代码结构呢?我们不是都知道“如果它没有坏,就不要去修理它!”吗? 每一个软件模块都有3项职责.第一个职责是它运行起来所完成的功能.这也是该模块得以存在的原因.第二个职责是它要应对的变化.几乎所有的模块在它们的生命周期中都要变化,开发者有责任保证这种变化应尽可能地简单.一个难以改变的模块是有问题的,即使能够工

敏捷软件开发:原则、模式与实践——第16章 对象图、第17章 用例、第18章 顺序图

第16章 对象图 有时,呈现出系统在某个特定时刻的状态是非常有用的.和一个正在运行系统的快照类似.UML对象图展示了在一个给定时刻获取到的对象.关系和属性值. 不过,你应该对花太多的对象图保持警惕.在大部分的情况下,它们都可以从相应的类图中直接推导出来,因此没有多少用处. 第17章 用例 在所有的UML图中,用例图是最令人迷惑也是最没有用处的.我建议出来系统边界外,忽略掉所有其他的图.系统边界图示例如下: 大矩形是系统边界.矩形内的所有东西都是将要开发的系统的组成部分.矩形外面是操作系统的参与者

敏捷软件开发:原则、模式与实践——第15章 状态图

第15章 状态图 在描述有限状态机(FSM)方面,UML提供个丰富的符合. 15.1 基础知识 下图是一个简单的状态迁移图(STD),该图描述了控制用户登录到系统的FSM.圆角矩形表状态.上层格间放置每个状态的名字.下层格间中放置的是一些特定动作,表示当进入或退出该状态时要做什么. 图中左上角的实心圆称为初始伪状态.FSM从这个伪状态开始,根据变迁规则进行转移. 15.1.1 特定事件 状态图的下层格间含有事件/动作对. 15.1.2 超状态 当许多状态以同样的方式响应某些同样的事件时,使用超状

敏捷软件开发:原则、模式与实践——第20章 咖啡的启示

第20章 咖啡的启示 这个例子对于教学有很多好处.它短小.易于理解并且展示了如何应用面向对象设计原则去管理依赖和分类关注点.但从另一方面来说,它的短小也意味着这种分离带来的好处可能抵不过其成本.就当做一个设计思路来看吧. 20.1 Mark IV型专用咖啡机20.1.1 规格说明书 Mark IV型专用咖啡机一次可以产出12杯咖啡.使用者把过滤器放置在支架上,在其中装入研磨好的咖啡,然后把支架推入其容器中.接着,使用者向滤水器中倒入12杯水并按下冲煮(Brew)按钮.水一直加热到沸腾.不断产生的

敏捷软件开发:原则、模式与实践——第9章 OCP:开放-封闭原则

第9章 OCP:开放-封闭原则 软件实体(类.模块.函数等)应该是可以扩展的,但是不可修改. 9.1 OCP概述 遵循开放-封闭原则设计出的模块具有两个主要特征: (1)对于扩展是开放的(open for extension).这意味着模块的行为是可以扩展的.当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为. (2)对于修改是封闭的(closed for modification).对模块进行扩展时,不必改动模块的源代码或者二进制代码.模块的二进制可执行版本,无论是可链接

敏捷软件开发:原则、模式与实践——第4章 测试

第4章 测试 编写单元测试是进行验证,更是进行设计.同样,它更是在编写文档.编写单元测试终结了许多反馈循环,尤其是功能验证方面的反馈循环. 4.1 测试驱动开发 假设我们遵循如下3条简单规则: (1)除非编写了一个不能通过的单元测试,否则不编写任何产品代码. (2)只要编写正好导致测试不通过或者编译失败的单元测试就够了,无需再多. (3)只要编写能够正好使失败的单元测试通过的商品代码就够了,无需再多. 如果遵循这些规则,我们就是以非常短的迭代周期进行工作.我们仅仅编写刚好不能通过的单元测试,接着

敏捷软件开发:原则、模式与实践——第19章 类图

第19章 类图 19.1 基础知识19.1.1 类 类一般表示成下面的样子: 分成格间的类图标以及对应的代码 注意类图标中变量和函数名前面的符合.(-)表示private:(#)表示protected:(+)表示public. 19.1.2 关联 类之间的关联表示的是那些持有对其他对象引用的实例变量.如phone和Button之间的关联: 一个PhoneBook对象和多个PhoneNumber对象相连(星号表示许多): 19.1.3 继承 UML中所有的箭头都指向源代码依赖的方向.类和类之间的继