收藏 分享(赏)

面向对象设计学习笔记.doc

上传人:myw993772 文档编号:6977199 上传时间:2019-04-29 格式:DOC 页数:15 大小:284KB
下载 相关 举报
面向对象设计学习笔记.doc_第1页
第1页 / 共15页
面向对象设计学习笔记.doc_第2页
第2页 / 共15页
面向对象设计学习笔记.doc_第3页
第3页 / 共15页
面向对象设计学习笔记.doc_第4页
第4页 / 共15页
面向对象设计学习笔记.doc_第5页
第5页 / 共15页
点击查看更多>>
资源描述

1、面向对象的设计学习笔记一些面向对象的设计法则第 2 页 共 15 页法则 1:优先使用(对象)组合,而非(类)继承 Favor Composition Over Inheritance 组合 (对象)组合是一种通过创建一个 组合 了其它对象的对象,从而获得新功能的复用方法。 将功能委托给所组合的一个对象,从而获得新功能。 有些时候也称之为“聚合” (aggregation)或“包容” (containment) ,尽管有些作者对这些术语赋予了专门的含义 例如: 聚合:一个对象拥有另一个对象或对另一个对象负责(即一个对象包含另一个对象或是另一个对象的一部分) ,并且聚合对象和其所有者具有相同的生

2、命周期。(译者注:即所谓的“同生共死”关系,可参见 GOF 的 Design Patterns: Elements of Reusable Object-Oriented Software 的引言部分。 ) 包容:一种特殊类型的组合,对于其它对象而言,容器中的被包含对象是不可见的,其它对象仅能通过容器对象来访问被包含对象。 (Coad) 包含可以通过以下两种方式实现: 根据引用(By reference) 根据值(By value) C允许根据值或引用来实现包含。 但是在 Java 中,一切皆为对象的引用!组合的优点和缺点 优点: 容器类仅能通过被包含对象的接口来对其进行访问。 “黑盒”复用,

3、因为被包含对象的内部细节对外是不可见。 对装性好。 实现上的相互依赖性比较小。 (译者注:被包含对象与容器对象之间的依赖关系比较少) 每一个类只专注于一项任务。 通过获取指向其它的具有相同类型的对象引用,可以在运行期间动态地定义(对象的)组合。一些面向对象的设计法则第 3 页 共 15 页 缺点: 从而导致系统中的对象过多。 为了能将多个不同的对象作为组合块(composition block)来使用,必须仔细地对接口进行定义。继承 (类)继承是一种通过扩展一个已有对象的实现,从而获得新功能的复用方法。 泛化类(超类)可以显式地捕获那些公共的属性和方法。 特殊类(子类)则通过附加属性和方法来进

4、行实现的扩展。继承的优点和缺点 优点: 容易进行新的实现,因为其大多数可继承而来。 易于修改或扩展那些被复用的实现。 缺点: 破坏了封装性,因为这会将父类的实现细节暴露给子类。 “白盒”复用,因为父类的内部细节对于子类而言通常是可见的。 当父类的实现更改时,子类也不得不会随之更改。 从父类继承来的实现将不能在运行期间进行改变。Coad 规则仅当下列的所有标准被满足时,方可使用继承: 子类表达了“是一个的特殊类型” ,而非“是一个由所扮演的角色” 。 子类的一个实例永远不需要转化(transmute)为其它类的一个对象。 子类是对其父类的职责(responsibility)进行扩展,而非重写或废

5、除( nullify) 。 子类没有对那些仅作为一个工具类(utility class)的功能进行扩展。 对于一个位于实际的问题域(Problem Domain)的类而言,其子类特指一种角色(role) ,交易( transaction)或设备(device) 。一些面向对象的设计法则第 4 页 共 15 页继承/组合示例 1 “是一个的特殊类型” ,而非“是一个由所扮演的角色” 失败。乘客是人所扮演的一种角色。代理人亦然。 永远不需要转化 失败。随着时间的发展,一个 Person 的子类实例可能会从 Passenger 转变成Agent,再到 Agent Passenger。 扩展,而非重写

6、和废除 通过。 不要扩展一个工具类 通过。 在问题域内,特指一种角色,交易或设备 失败。Person 不是一种角色,交易或设备。继承并非适用于此处!使用组合进行挽救!一些面向对象的设计法则第 5 页 共 15 页继承/组合示例 2 “是一个的特殊类型” ,而非“是一个由所扮演的角色” 通过。乘客和代理人都是特殊类型的人所扮演的角色。 永远不需要转化 通过。一个 Passenger 对象将保持不变; Agent 对象亦然。 扩展,而非重写和废除 通过。 不要扩展一个工具类 通过。 在问题域内,特指一种角色,交易或设备 通过。PersonRole 是一种类型的角色。一些面向对象的设计法则第 6 页

7、 共 15 页继承适用于此处!继承/组合示例 3 “是一个的特殊类型” ,而非“是一个由所扮演的角色” 通过。预订和购买都是一种特殊类型的交易。 永远不需要转化 通过。一个 Reservation 对象将保持不变;Purchase 对象亦然。 扩展,而非重写和废除 通过。 不要扩展一个工具类 通过。 在问题域内,特指一种角色,交易或设备 通过。是一种交易。继承适用于此处!一些面向对象的设计法则第 7 页 共 15 页继承/组合示例 4 “是一个的特殊类型” ,而非“是一个由所扮演的角色” 失败。预订不是一种特殊类型的 observable。 永远不需要转化 通过。一个 Reservation

8、对象将保持不变。 扩展,而非重写和废除 通过。 不要扩展一个工具类 失败。Observable 就是一个工具类。 在问题域内,特指一种角色,交易或设备 不适用。Observable 是一个工具类,并非一个问题域的类。 。继承并非适用于此处!继承/组合总结 组合与继承都是重要的重用方法 在 OO 开发的早期,继承被过度地使用 随着时间的发展,我们发现优先使用组合可以获得重用性与简单性更佳的设计 当然可以通过继承,以扩充(enlarge)可用的组合类集( the set of composable classes) 。 因此组合与继承可以一起工作 但是我们的基本法则是:优先使用对象组合,而非(类)

9、继承 Favor Composition Over Inheritance 一些面向对象的设计法则第 8 页 共 15 页法则 2:针对接口编程,而非(接口的)实现 Program To An Interface, Not An Implementation 接口 接口 是一个对象在对其它的对象进行调用时所知道的方法集合。 一个对象可以有多个接口(实际上,接口是对象所有方法的一个子集) 类型 是对象的一个特定的接口。 不同的对象可以具有相同的类型,而且一个对象可以具有多个不同的类型。 一个对象仅能通过其接口才会被其它对象所了解。 某种意义上,接口是以一种非常局限的方式,将“是一种”表达为“一种

10、支持该接口的” 。 接口是实现插件化(pluggability )的关键实现继承和接口继承 实现继承 ( 类继承 ):一个对象的实现是根据另一个对象的实现来定义的。 接口继承 ( 子类型化 ):描述了一个对象可在什么时候被用来替代另一个对象。 C+的继承机制既指类继承,又指接口继承。 C+通过继承纯虚类来实现接口继承。 Java 对接口继承具有单独的语言构造方式Java 接口。 Java 接口构造方式更加易于表达和实现那些专注于对象接口的设计。接口的好处 优点: Client 不必知道其使用对象的具体所属类。 一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。 对象间的连接不必硬绑

11、定(hardwire)到一个具体类的对象上,因此增加了灵活性。 松散藕合(loosens coupling) 。 增加了重用的可能性。 提高了(对象)组合的机率,因为被包含对象可以是任何实现了一个指定接口的类。 缺点: 设计的复杂性略有增加一些面向对象的设计法则第 9 页 共 15 页(译者注:接口表示“像” (LikeA)的关系,继承表示“是” (IsA)的关系,组合表示“有” (HasA)的关系。 )接口实例 该方法是指其它的一些类可以进行交通工具的驾驶,而不必关心其实际上是(汽车,轮船,潜艇或是其它任何实现了 IManeuverabre 的对象) 。法则 3:开放封闭法则(OCP)软件组

12、成实体应该是可扩展的,但是不可修改的。 Software Entities Should Be Open For Extension, Yet Closed For Modification 一些面向对象的设计法则第 10 页 共 15 页开放封闭法则 开放-封闭法则认为我们应该试图去设计出永远也不需要改变的模块。 我们可以添加新代码来扩展系统的行为。我们不能对已有的代码进行修改。 符合 OCP 的模块需满足两个标准: 可扩展,即“对扩展是开放的” (Open For Extension)模块的行为可以被扩展,以需要满足新的需求。 不可更改,即“对更改是封闭的” (Closed for Mod

13、ification)模块的源代码是不允许进行改动的。 我们能如何去做呢? 抽象(Abstraction) 多态(Polymorphism) 继承(Inheritance) 接口(Interface ) 一个软件系统的所有模块不可能都满足 OCP,但是我们应该努力最小化这些不满足OCP 的模块数量。 开放封闭法则是 OO 设计的真正核心。 符合该法则便意味着最高等级的复用性(reusability)和可维护性(maintainability) 。OCP 示例 考虑下面某类的方法: 以上函数的工作是在制订的部件数组中计算各个部件价格的总和。 若 Part 是一个基类或接口且使用了多态,则该类可很容

14、易地来适应新类型的部件,而不必 对其进行修改。 其将符合 OCP 但是在计算总价格时,若财务部颁布主板和内存应使用额外费用,则将如何去做。 下列的代码是如何来做的呢?一些面向对象的设计法则第 11 页 共 15 页 这符合 OCP 吗? 当每次财务部提出新的计价策略,我们都不得不要修改 totalPrice()方法!这 并非 “对更改是封闭的” 。显然,策略的变更便意味着我们不得不要在一些地方修改代码的,因此我们该如何去做呢? 为了使用我们第一个版本的 totalPrice(),我们可以将计价策略合并到 Part 的getPrice()方法中。 这里是 Part 和 ConcretePart

15、类的示例: 但是现在每当计价策略发生改变,我们就必须修改 Part 的每个子类! 一个更好的思路是采用一个 PricePolicy 类,通过对其进行继承以提供不同的计价策略:一些面向对象的设计法则第 12 页 共 15 页 看起来我们所做的就是将问题推迟到另一个类中。但是使用该解决方案,我们可通过改变 Part 对象,在运行期间动态地来设定计价的策略。 另一个解决方案是使每个 ConcretePart 从数据库或属性文件中获取其当前的价格。单选法则单选法则(the Single Choice Principle)是 OCP 的一个推论。单选法则:无论在什么时候,一个软件系统必须支持一组备选项,

16、理想情况下,在系统中只能有一个类能够知道整个的备选项集合。一些面向对象的设计法则第 13 页 共 15 页法则 4:Liskov 替换法则(LSP)使用指向基类(超类)的引用的函数,必须能够在不知道具体派生类(子类)对象类型的情况下使用它们。 Function Thar Use Referennces To Base(Super) Classes Must Be Able To Use Objects Of Derived(Sub) Classes Without Knowing It Liskov 替换法则 显而易见,Liskov 替换法则( LSP)是根据我所熟知的“多态”而得出的。 例如

17、: 方法 drawShape 应该可与 Sharp 超类的任何子类一起工作(或者,若 Sharp 为 Java 接口,则该方法可与任何实现了 Sharp 接口的类一起工作) 但是当我们在实现子类时必须要谨慎对待,以确保我们不会无意中违背了 LSP。 若一个函数未能满足 LSP,那么可能是因为它显式地引用了超类的一些或所有子类。这样的函数也违背了 OCP,因为当我们创建一个新的子类时,会不得不进行代码的修改。LSP 示例 考虑下面 Rectangle 类:一些面向对象的设计法则第 14 页 共 15 页 现在,Square 类会如何呢?显然,一个正方形是一个四边形,因此 Square 类应该从R

18、ectangle 类派生而来,对否?让我们看一看! 观察可得: 正方形不需要将高和宽都作为属性,但是总之它将继承自 Rectangle。因此,每一个 Square 对象会浪费一点内存,但这并不是一个主要问题。 继承而来的 setWidth()和 setHeight()方法对于 Square 而言并非真正地适合,因为一个正方形的高和宽是相同。因此我们将需要重写 setWidth()和 setHeight()方法。不得不重写这些简单的方法有可能是一种不恰当的继承使用方式。 Square 类如下: 看起来都还不错。但是让我们检验一下!一些面向对象的设计法则第 15 页 共 15 页 测试程序输出:

19、看上去好像我们违背了 LSP! 这里的问题出在哪里呢?编写 testLsp()方法的程序员做了一个合理的假设,即改变Rectangle 的宽而保持它的高不变。 在将一个 Square 对象传递给这样一个方法时产生了问题,显然是违背了 LSP Square 和 Rectangle 类是相互一致和合法的。尽管程序员对基类作了合理的假设,但其所编写的方法仍然会导致设计模型的失败。 不能孤立地去看待解决方案,必须根据设计用户所做的合理假设来看待它们。 一个数学意义上的正方形可能是一个四边形,但是一个 Square 对象不是一个 Rectangle对象,因为一个 Square 对象的行为与一个 Rectangle 对象的行为是不一致的! 从行为上来说,一个 Square 不是 一个 Rectangle!一个 Square 对象与一个 Rectangle 对象之间不具有多态的特征。总结 Liskov 替换法则(LSP)清楚地表明了 ISA 关系全部都是与行为有关的。 为了保持 LSP(并与开放封闭法则一起) ,所有子类必须符合使用基类的 client 所期望的行为。 一个子类型不得具有比基类型(base type)更多的限制,可能这对于基类型来说是合法的,但是可能会因为违背子类型的其中一个额外限制,从而违背了 LSP! LSP 保证一个子类总是能够被用在其基类可以出现的地方!

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报