第6章-设计原则

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第六章 设计原则
常文萃 01@163
*
*单一职责原则 *开放封闭原则 *里氏替换原则 *依赖倒转原则 *迪米特法则 *接口隔离原则
单一职责原则( 简称) 1. 核心思想
就一个类而言,应该仅有一个引起它变化的原因。 2. 产生原因
之所以会出现单一职责原则就是因为在软件设计时会出现以下类似 场景:
T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生 改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生 故障。也就是说职责P1和P2被耦合在了一起。
如果高层模块和低层模块都依赖于抽象(接口或抽象类),只 要接口稳定,那么任何一个更改都不用担心其他受到影响了。
2)针对接口编程而不是针对实现编程意义
我们现在使用的电脑有各式的品牌,联想、神舟、戴尔等等,电 脑需要用到鼠标,键盘;假设鼠标、键盘是针对某一个品牌的机器 实现去做的话,那么市面上的键盘和鼠标就都是各式各样的,有一 天鼠标或键盘坏了,我们要记住这个电脑是什么品牌、什么型号的 再去买,很麻烦。
有人会说,企鹅不能飞很正常啊,只要在使用这个类的客户代码中 加一句判断就行了。但是,客户代码和“企鹅”的代码很有可能不是同 时设计的,在当今软件外包一层又一层的开发模式下,你甚至根本不知 道两个模块的原产地是哪里,也就谈不上去修改客户代码了。客户程序 很可能是遗留系统的一部分,很可能已经不再维护,如果因为设计出这 么一个“企鹅”而导致必须修改客户代码,谁应该承担这部分责任呢? 修改客户代码直接违反了开闭原则。所以,违反里氏代换原则将使既有 的设计不能封闭!
继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽 象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要 求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意 修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一 层含义。
六、接口隔离原则(补充)
接口隔离原则( , 缩称)
3. 解决办法 遵守单一职责原则,将不同的职责封装到不同的类或模
块中。
4. 举例 开发一个俄罗斯方块游戏,要考虑将程序分为游戏逻辑
和界面逻辑两个类。游戏逻辑指表示游戏区域的数组中每一 项值变化的问题,如下落、旋转、碰撞检测、移动等;界面 逻辑负责根据数组的数据进行绘制和擦除等。
2.产生原因
“需求总是变化的”、“世界上没有一个软件是不变的”, 因此对于软件设计者来说,必须在不修改原有系统的情况下, 实现灵活的系统扩展。
3. 实施办法
只有依赖于抽象。实现开放封闭的基本思路就是对抽象编 程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的 抽象,所以对修改就是封闭的;而通过面向对象的继承和多态 机制,可以实现对抽象体的继承,通过覆写其方法来改变固有 行为,实现新的扩展方法,所以对于扩展就是开放的。
1)如何理解高层模块不应该依赖低层模块,两者都应该依赖于抽象
在面向Hale Waihona Puke Baidu程的开发中,为了使常用的代码可复用,一般都会把 这些常用的代码写成许许多多函数的程序库,这样做新项目的时候 调用这些函数就可以了。
例如:我们做的项目大多要访问数据库,所以我们就把数据库的代 码写成了函数,每次做新项目时就去调用这些函数,这就是高层依 赖于低层模块。问题是,我们在做新项目的时候,会发现业务逻辑 的高层模块是一样的,我们希望能重用这些高层模块,但是这些高 层模块和低层模块的数据库绑定在一起了,这样就没办法复用这些 高层模块。
2. 接口隔离原则与单一职责原则的区别 1)单一职责原则注重的是职责;而接口隔离原则注重对接口依 赖的隔离。
2)单一职责原则主要是约束类,其次才是接口和方法,它针对 的是程序中的实现和细节;而接口隔离原则主要约束接口接口, 主要针对抽象,针对程序整体框架的构建。
现在的电脑基本上都是使用接口,无论是键盘也好,鼠标也好, 只要买接口的就可以使用。同时,使用接口还可以有其他的扩展, 例如,实现了接口的小台灯,只要接上线就可以照明、实现了接口 的充电器,接到电脑上就可以充电。
一些生活中的例子: 1、插槽。主板和显卡之间关系的抽象。 主板和显卡通常是使用插槽来连接的,只要接口适配,不管是主板 还是显卡更换,都不是问题。 2、驾照。司机和汽车之间关系的抽象。
有驾照的司机可以驾驶各种汽车。 3、电源插座。
2. 实现方法 在实际编程中,一般需要做到如下3点: 低层模块尽量都要有抽象类或接口,或者两者都有。 变量的声明类型尽量是抽象类或接口。 使用继承时遵循里氏替换原则。
一句话,依赖倒转原则的核心就是要面向接口编程。
3. 解决方案 降低类之间的耦合。一个软件实体应当尽可能少的与
其他实体发生相互作用。每一个软件单位对其他的单位都 只有最少的知识,而且局限于那些与本单位密切相关的软 件单位。
由于每个类尽量减少对其他类的依赖,因此,很容易 使得系统的功能模块功能独立,相互之间不存在(或很少 有)依赖关系。
例:对于鸟类 和企鹅类,如果鸟类中有个方法,企鹅自然也继承了这个 方法,可企鹅不能飞,于是我们在企鹅的类中覆盖了方法,告诉方法的 调用者:企鹅是不会飞的。这完全符合常理。但是,这违反了,企鹅是 鸟的子类,可是企鹅却不能飞!(此处的“鸟”不再是生物学中的鸟, 它是软件中的一个类、一个抽象)
1. 核心思想 客户端不应该依赖它不需要的接口;一个类对另一个类
的依赖应该建立在最小的接口上。
具体来说,要为各个类建立专用的接口,而不要试图去 建立一个很庞大的接口供所有依赖它的类去调用。在程序设 计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。 接口是设计时对外部设定的“契约”,通过分散定义多个接 口,可以预防外来变更的扩散,提高系统的灵活性和可维护 性。
一般来讲, 假设 有一功能P1,由A类完成。现需要将功能P1进行扩 展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。新功能P 由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致 原有功能P1发生故障(有可能改写了原来的方法)。 2. 解决方案
当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方 法完成新增功能P2外,尽量不要重写父类A的方法。
相关文档
最新文档