《面向对象程序构造》的中文摘要

object oriented software construction的作者是Eiffel的创造者Bertrand Meyer,这本书是当前关于向对象程序设计最全的,被称为OO设计圣经,可惜该书没有中文版,俺买了一本,花了一天看了一半,作了一些读书笔记,现在写在Blog上,有益于大家参照

面向对象程序构造

第一章    软件质量

1、  软件质量可以分为:外在质量和内在质量

外在质量主要是指用户如何看待和使用一个软件,包括易用性、效率等

内存质量则指软件的结构对于开发人员的感觉。

外在质量是一个软件的根本,它是一个软件是否有价值的根本衡量标准。

 

 

个人观点:

u       虽然外在质量是衡量一个软件价值的根本标准,但是对于一个中大型软件,没有内在的质量,根本就无法保证外在质量。对于小软件,可能内在质量不能决定外在质量,对中大型软件,必须先保证内在质量。

 

 

2、  软件外在质量的组成内容

²        正确性

没有正确性,表示软件不能完成用户所期望的事情,软件就没有存在的价值和必要性。因此正确性是第一位的。

“分层”是一个比较好的模式,可以通过它来保证软件的正确性,保证每一层和层之间逻辑关系的正确性,这样可以保证软件的正确性。就好像“操作系统编译器--代码类库”就是最基本的层结构,如果每一层都正确,则开发出来的软件就可以执行正确的功能。

 

 

个人观点:

u       分层容易模块化,是一种类似AOP的分析方法

u       容易定位和修改错误,因为每层负责的内容不一样,因此出现的错误也很容易定位

u       因为每一层的功能不一样,所以接口必须明确,对于通过规范明确描述的接口,很容易替换一个层。

 

 

²        容错性(鲁棒性)

当不在系统可以预测的错误发生时,系统必须保证正确性。

 

 

个人观点:

u       因为错误在软件使用中会发生,而且软件自身也一定存在BUG,个人觉得“宁愿崩溃,也不要继续执行,因为崩溃的系统不再继续运行,不会犯逻辑错误,错误数据比较容易恢复,但是如果犯错的系统犯了逻辑错误,数据就很难恢复”。

 

 

²        扩展性

传统软件设计时,认为在开始设计时能通过调研确定所有需求,所以在变化发生时难以应对。

两个原则

u       设计尽量简单一些

u       功能分解而非集中

 

 

个人观点:

u       设计的简单度如何控制。

 

 

²        复用性

个人观点:

u       用的人越多,潜在的问题被发现的机会就越大。

u       复用的粒度如何控制,业务级,模块级、代码级等。

 

 

²        兼容性

基本内容:

u       标准化文件格式

u       标准化数据结构

u       标准化用户接口

 

 

个人观点:

u       XML是否可以完成以上三者的标准化。

 

 

²        效率

过早的优化可能会产生问题,事实上大部分时间不需要优化,可以参照下面的数据--《软件维护费用比例》。

 

 

个人观点:

u       先使系统模块化,容易进行模块化

u       只有在集成测试时发现效率问题,才进行优化工作。

       

²        易用性

你我都不是用户,不能从自己的角度出发来揣测。

 

 

个人观点:

u       如果自己没有把握做好内容的话,干脆模仿别人,如菜单风格,快捷键等,模仿一些类似的软件。

 

 

²        功能性

u       不能因为添加新功能,而影响了软件的一致性,特别是产品,无论在功能上有什么改变,也不应该引起用户在操作上的大幅改变。

u       决不能只关注新功能而忽略其它方面的质量。

 

 

²        最后期限

 

 

²        验证性

 

 

²        完整性

保证数据的安全和完整,不能被无关人员访问。

²        恢复性

个人观点:

u       软件一定会有问题,但问题的解决时间,数据恢复速度和完整性都表示了一个软件的质量。

 

 

²        文档

1.         外部文档----------à给用户

2.         内部文档----------à给开发者

3.         模块接口文档----à给开发者

个人观点:

u       23都是内部文档,3有可能公布给第三方。但2的目的是了解整个系统的结构及相关模块,而3是模块的详细信息。

 

 

3、  权衡(妥协TradeOff

前面所提到的因素,在软件开发中相互影响,但鱼与熊掌无法兼得,所以开发人员必须做出权衡,将注意力集中在最几个因素,但“正确性”是不可以妥协的。

 

 

软件质量因素中最重要的四个:

u       正确性

u       容错性

u       扩展性

u       复用性

 

 

软件维护费用比例

1)        用户需求变更        41.8%

2)        数据格式变更        17.6%

3)        紧急修复               12.4%

4)        定期修复               9%

5)        硬件变更               6.2%

6)        文档                      5.5%

7)        效率改善               4%

8)        其它                      3.4%

个人观点:

u       1257应该都归入“需求变更”

u       34应该归入“BUG修复或功能改善”

u       好的扩展性减少“需求变更”的代价

u       复用度高减少“BUG修复”成本。

 

 

4、  本章要点

软件工程的目的就是为了建立好的软件。

质量并非由一个因素决定,而是多个因素

评测软件外在质量和内在质量时必须分开,因为二者的评价者不一样,前者是用户,后者是开发人员

外在质量决定软件质量,但必须通过好的软件内在质量来通到好的外在质量

 

 

第二章    面向对象标准

一、方法与语言

1.         面向对象并非单独存在,它贯穿于软件开发周期,从分析到设计。

 

 

个人观点:

u       无论OOA还是OODOOP都表明一点,如果使用面向对象技术,面向对象就应该从头到尾

 

 

2.         断言

对前置条件、后置条件和常量的确认

 

 

个人观点:

u       没有语言级支持或者是工具级的支持,断言便难以实现。

 

 

3.        

类是面向对象的核心所在,因为每一个对象都代表了一个独立的个体,也就是一个小的模块。

它的基本用途,或者说职责就是“功能调用”,通过“功能调用”来完成自己的职责,“功能调用”大多数时候通过“函数”来体现的。

 

 

个人观点:

u       设计类时有个基本原则---“数据尽可能是私有,而对外的方法就尽可能的少”,因为类是一个个体,每一个公开的方法就代表了一个职责,不必要的职责是不需要加以描述的。

u       DTO是否会是一个例外

 

 

4.         信息隐藏

 

 

5.         异常处理

语言必须为异常的恢复提供管理机制

 

 

个人观点:

u       不是很明白这个说法,机制到底指什么

 

 

6.         强类型约束

变量、方法、参数在声明时,必须明确,能够通过编译或工具进行检查。

 

 

个人观点:

u       强类型约束可能会带来一个好处,因为为了减少约束,会让开发人员使用接口声明变量和参数。

u       有时在想能不能有一个方法,可以对一个类进行两个或多个约束,即传入参数和声明变量时,可以让参数和变量同时满足多个接口。比如说传入一个参数时,你可能即希望它是A类型,又是B类型,但目前做不到,至少Java做不到。

 

 

7.         泛型

有助于减少强类型约束带来的一些不好的后果

 

 

个人观点:

u       java中常用的集合类是不作类型检查的,可能会引起潜在的问题,Java1.5引入泛型会带来什么样的改变

 

 

8.         继承

多继承有可能引起二义性

 

 

个人观点:

u       有没有好的办法,在引入多继承时,去除二义性,C++中的方法过于复杂。

 

 

9.         带有约束的泛型

 

 

10.     重定义(override

一个子类能够重新定义从父类继承的方法,是多态的基础。

11.     多态

 

 

12.     动态绑定

 

 

13.     运行期类型鉴定

 

 

14.     延缓实现功能

面向对象必须提供一种机制,能够使得功能和类能够有一个定义来描述类的外部行为,但不限定具体的实现。

 

 

个人观点:

u       正是这种机制提供了“数据抽象功能”,从而有“接口”和“抽象类”

 

 

15.     内存管理和垃圾收集

个人观点:

u       C++部分支持垃圾收集,由程序员控制(如STL),有更高的灵活性,但与Java的完全管理,哪个更好?

u       我感觉干脆就由程序完全控制或者由系统完全控制,否则可能会发生其它的问题。

 

 

二、实现及运行环境

1、  自动更新

当类的定义有所变更时,系统能够自动更新相关内容。

 

 

个人观点:

u       编译期的更新是必须的,但像Java Webstart这种技术保持软件级的更新,应该说与面向对象是无关的。

 

 

2、  增量更新

大系统开发时,不能因为小的更新的全部更新,只需要对受影响的部分进行更新。

 

 

个人观点:

u       类本身就是独立的个体,只有在对外接口改变时才需要更新相关的类。

u       Eclipse的自动重构是一种新的更新方法,避免手工实现的耗时和可能引起的错误。

 

 

3、  持久化机制

如果类间存在引用关系,则必须有一种持久化机制保证所有引用关系的对象都能被正确持久化。

 

 

个人观点:

u       面向对象数据库是不是一个好的解决方案。

u       通过一种机制将自动将类持久化到关系数据库,是一种通过桥接的方式来实现对象数据库,可能也是一种方案。

 

 

4、  文档

代码<---------->文档 两者保持一致性

 

 

个人观点:

u       除了Javadoc之类的方式在源代码和文档间保持一致外,通过反向工程在二进制代码与UML之间保持一致。反射的引入可能会使得反向工程脱离了实际设计。

 

 

三、类库

1、  基本类库

提供基本的数据和算法,避免重复发明轮子

 

 

个人观点:

u       C++发布时没有提供一个基本类库,是C++最大的失败,造成今天C++的复杂库。

 

 

2、  人机接口

如果将人机接口统一化,也会有效地减少“修改”的代价

 

 

个人观点:

u       UI往往与OS相关,很难统一的,特别是跨平台问题,象QT的方法比较好

u       C++之父B.S说得好,Java不跨平台,它本身就是一个平台,就是一个OS

 

 

3、  类库的发展

在一个类库发布以后,进行更新时,必须尽量的保证接口标准不变。

 

 

个人观点:

u       引入类库版本管理解决这个问题(.NET引入了版本管理)

u       在发布补丁时接口应该不变,但是新版本应该可以改变接口。过分的保证接口,会带来更多的麻烦。

 

 

第三章    模块化处理

一、模块化的五个标准

1、  系统分解成模块

分解的考虑

u       模块间依赖最小化

u       模块间的依赖必须明确

自行而下的设计方法,通常一个树状的模块结构

 

 

个人观点:

u       AOP的竖切分析与自上而下的横切分析必须结合,才能做到好的模块分解

u       自上而下的分析往往是业务级的,有很多限制

 

 

2、  系统组合

“系统组合”并不是“系统分解”的反方向,它强调的是一种复用,使用已有的模块组合成新的系统,“组合”和“分解”必须结合起来一切开发。

      

个人观点:

u       系统组合更象AOP的思考方式,竖切后进行复用及组合

 

 

3、  模块的可理解性

一个模块的可理解性这样定义:当一个开发者在不需要查看或只需要查看很少的模块就可以清楚地理解一个模块

 

 

个人观点:

u       系统组合更象AOP的思考方式,竖切后进行复用及组合

u       参数越少,涉及的模块也就越少,可理解性也就越强

u       规范有助于理解

 

 

4、  模块相关性

模块的相关性由它改变时对其它模块的影响来决定

 

 

个人观点:

u       多用接口和抽象类,少用实际类,也就是说用规范来定义模块而非实现。

 

 

5、  模块安全性

必须对入口数据及对象予以确认(断言),也尽量保证输出的有效性。

 

 

个人观点:

u       如果输入数据不合法,必须有明确提示,或者抛出异常,也就是说如果问题,必须给出明确的信息,否则会带来更多的麻烦。

 

 

 

 

二、模块化的五个规则

1、  映射

系统中的模块应可能的与问题域中的问题进行映射,这样有助于软件模型更接近于问题模型。

 

 

个人观点:

u       感觉是横切的概念

 

 

2、  接口越少越好

一个模块公布出来的接口越少越好,除了尽可能少的接口以外,还将接口加上一定的限制,只公布给有一定权限的模块,比如说JavaPackageC#aasemblyC++friend

 

 

个人观点:

u       用环状或星状模型,以及设计模式,避免网状模型,这样有助于减少接口的数量和相关模块,mediatorfaçade模式都有助处理这一点

 

 

3、  接口明确

明确接口有助于理解模块间关系

三、五个原则

1、  模块语言接口描述一致性

模块的实现可能有多个语言,但模块间接口的主义必须一致

 

 

个人观点:

u       COMCORBA是典型的例子,但是COM的描述也存在歧义

u       Web ServiceWSDL描述可能会更好

 

 

2、  自我描述

设计者应尽可能地使模块的所有信息能通过自身描述

 

 

个人观点:

u       以往的二进制级的模块只能提供运行信息,通过UML反向,可能有设计或模块级描述,再通过Javadoc技术,就有代码级的描述

u       如果软件引入过多的动态性,如Java中的反射,反向工程的准确性就值得怀疑。

 

 

3、  一致的访问语义

4、  开闭原则

对修改开放,对调用关闭,也就是说接口不变,实现可变。

 

 

个人观点:

u       实现必须是容易扩展,甚至是可配置的,减少static方法,如果一定要用,通过singleton来用,但是singleton容易被滥用,Spring框架进行管理会是一个新的趋势。

 

 

 

 

5、  自行管理

如果一个模块需要实现“开闭原则”,就必须对自己接口的实现进行管理

 

 

个人观点:

u       一个模块可以看作两个部分,一个是对外接口,也就是模块功能的规范和描述;另一个是管理者,对接口的实现进行管理。

 

 

第四章    软件复用

一、复用的益处

1、  节省开发时间

2、  节省维护费用

3、  提高可靠性

4、  运行效率

5、  一致性

6、  资金的节省

 

 

二、复用的类型

1、  开发人员间的重用,往往是经验级的重用

 

 

2、  设计与标准的重用

这一级的重用比上一级有组织,类似于模块级的重用

 

 

3、  设计模式

思维方式和方案级的重用

 

 

4、  代码级的重用

个人观点:

u       重用代码,前提是理解别人的代码,成人比较高

u       重用代码,往往是知道细节的内容,与模块化思想背道而驰

u       有可能引入潜在的错误,而且修改成本较高

u       有业务的重用最好,否则有组件级,实在不行,有代码复用也总比没有好。简单的说,复用度再差,有总比没有好。

 

 

5、  抽象模块的复用

个人观点:

u       抽象模块的发现和整理以及粒度的控制如何处理和衡量。

 

 

三、模块结构重用的五个前提

1、  指定接口类型

模块应该支持多种类型的数据,否则仅能对一种数据类型提供功能。泛型的出现在很大程序上解决了这个问题。

 

 

个人观点:

u       通过接口化参数,同样可以做到,比如排序,将传入数据定义为基本对象接口,将排序接口也传为一个参数传入,这样将由模块进行逻辑处理,排序接口进行比较操作。这样更加灵活,但引入泛型也可以在一定程度上减少复杂度,也是必要的。

 

 

2、  提供多方案

如排序模块,不同的数据排序方案可能不同,应由用户根据需要自行决定

 

 

个人观点:

u       具体方案属于实现内容,如何暴露这些接口则要考虑

 

 

3、  实现的变化

如果当前模块有可能不能满足未来的需要,则它应该可以提供一种机制,使得开发者在不改变程序代码的前提下提供新的实现,或修改现有的实现。

 

 

4、  模块描述的独立性

一个模块的描述尽量稳定,不能因为其它模块的改变而改变,保证对用户的接口尽量不变。

 

 

5、  共性的抽取性

模块的抽象性决定了一个模块的适用范围

 

 

个人观点:

u       抽象度越高,模块适用范围越广,但复杂度相应提高,两者如何取舍?有一个权衡,过分的抽象引起的复杂度对用户的使用也是一个问题。

 

 

四、重载与泛型

1、  重载通过相同名称,不同参数来提供不同的实现,增强了语义的理解性,有助于降低模块的复杂度

 

 

个人观点:

u       C++的默认参数,有时优于重载,重载用得过多也会产生歧义,也容易被滥用。

 

 

2、  泛型的引入在提高抽象度的同时,不会增加模块规范的复杂度

 

 

第五章    面向对象技术

一、模块分解

自上而下地分解模块,降低了复用性,因为每一个功能点都对着一个确定的问题,过于注重实际解决问题,减少对抽象的关注。

 

 

个人观点:

u       模型分解必须横切和竖切,因为单独的应用很难做到抽象。

u       直接的抽象比较困难,先解决实际问题,再在此基础上进行抽象化处理,可能会更好一些。

 

 

二、Top-Down模型分解

这种开发模型有个默认前提问题已经明确,方案也自然得到,自上而下只是根据问题的解答方案给出实现方案,开发则是根据实现方案进行实现。

 

 

在真正的业务系统中,这个前提大部分时候都不满足,在算法处理和小型程序中,该模型可能会更更加适用。

 

 

三、对象与函数

个人观点:

u       面向对象技术之所以比过程技术更容易扩展,是因为对象是用规范来描述的,不涉及行为,而函数则直接给出了实现,给出的描述也是基于实现,而是抽象的。

u       函数间的协作及调用是通过数据结构传递信息的,因此数据都是public的,信息的隐藏比较困难,而且也难以保护。

 

 

四、面向对象提出的问题

1、  如何发现相关对象

u       许多对象都是现实中的实体的映射

u       对已有对象的复用

u       经验和感觉

2、  如何描述对象(即对象规范,外部接口)

u       抽象性、规范

u       将相应的函数和数据结构放入类中合适的位置

3、  如何描述对象间的关系和共性(引用和继承)

4、  如何使用对象构成软件

 

 

第六章    数据抽象

一、标准

1、  描述必须精确,无二义性

2、  描述必须完整

3、  不可过分描述

 

 

个人观点:

u       如果软件由多个语言协作开发,如何进行统一的描述,Web Service会是描述的银弹吗?

 

 

二、抽象数据的描述包括四个部分

1、  类型

类型的定义约束了对象间的协作,也保证了协作间的可靠性,通过泛型可能适当的放宽约束。

 

 

2、  功能

个人观点:

u       泛型应是数据级的泛化,而不是操作(方法)级的。

 

 

3、  公理

一个类或函数其功能必须有一定的理论支持,以断绝二义性。

 

 

4、  前置条件

行为只有在一定的环境下才能正确进行,前置条件用来确认环境,是接口“定义”不可或缺的一部分。

 

 

三、面向对象通过“数据抽象”说明一点

规范的定义并不是说明“你是什么”,而是“你有什么”,也就是“你能为我做什么”

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值