原文:
有些人认为,学习面向对象太难了,太花时间了。真的是这样吗?这些人说的困难,真是面向对象才有的吗?实际上,面向对象的一些基本原理,倒是适用于非面向对象的环境。甚至,你编写SHELL脚本的时候,你也能使用面向对象的基本技术来提高你产品的质量。
什么样的代码是才好的代码
评价代码的好坏,有许多要考虑的标准。但众多的标准与代码的灵活性(Flexibility)相关。灵活性是指:你可以容易地修改代码;容易把代码放在新环境中使用。
为什么代码需要灵活性?其实主要是因为人的因素。犯错误是人的本性。无论是书面的还是口头的交流,都常产生误解;需求也总是不断变化。使用了正确的方法,也会创造错误的东西,更何况,我们可能使用了错误的方法。
不管我们的愿望多么美好,总是不能在第一次就正确。我们寄希望新的编程语言,更好的开发方法,新的IDE,但最终总发现我们还是犯错误。我们应该清楚的知道,软件就是软的东西,它必须能容易修改。
Capers Jones,在他的一本书中说,需求的平均变化率为每月2%(现在这个数字应该有所增加)。但引起项目变化的因素,并非全因为“需求”的变化,有时候“需求”不过是替罪羊。
根
据对英国建造行业的调查,有30%的返工并因非因为需求的变化。这些返工都是由人为的错误导致的,而且还都是不断出现的老错误:一个托梁截短了2英寸;用
了错误型号的铁钉;搞错了窗户的位置。我们总会犯一些错误,这是人类的本性,无论一个软件的质量多么的好,我们总能对他改造完善。灵活的代码改变起来容
易,改变的原因可能是需求的变化,也可能是我们的错误。
在
面向对象程序的开发中,如何避免常见的错误?如何让软件保持灵活性?有很多东西要学。所有的这些课程总结成一句话“Keep it DRY, Keep
It shy,and tell the other
guy”。让我们来看看,这句话究竟什么意思,在面向对象的代码中,如何去使用这些原则。这些原则也不仅适用于面向对象的环境。
Keep It DRY 不要重复
这里说DRY 是Don't Repeat Yourself的简写。这是一个非常重要的原则:每一个程序中的要素,必须只有一个明确的,无二义的确定的表达。任何一个“知识点"必须只在唯一的地方明确体现。
也
就是说,对任何你设计的逻辑,做的任何决定,只明确的在一个地方体现。也许因为某种具体的原因,你必须有相似代码的多个物理拷贝,比如:对你设计的某个数
据结构,既有对应的表结构创建脚本,又要对应的C++类定义代码。这时,必须只有一个物理拷贝是权威的。一个理想的做法:所有非权威的物理拷贝都有一个源
头产生,使用代码生成工具自动产生。如:C++类的定义代码,由表结构的创建代码自动产生。即使不能做到这一点,也应该有一个权威的文档,对你设计的这种
数据结构进行说明。
使用上面的策略,当发生变化的时候,你只需要改变一个地方。避免了不必要的麻烦。否则,就有可能导致数据结构或处理逻辑的不一致,造成很难发现的bug。
DRY原则不但应用在编码上。也应用在开发者每天的其他工作上:编译程序,写文档,绘制数据库结构图,代码检查等等。
Keep It Shy 代码应该害羞
好的代码是非常害羞的,就像一个四岁大的孩子,总是藏在妈妈的后面,代码不应该过多的显露自己,不应该影响周围。
但是,你可能发现你的代码“成熟”的太快了,丢弃了他端庄的羞怯,变的像一个野孩子。当代码不再羞怯,是因为你加入了不必要的耦合。不正确的耦合包括:静态耦合,动态耦合,问题域耦合和临时耦合。
当一块代码需要另外的一块代码才能编译,这就造成静态耦合。一般情况下,不能说这不好,比较最简单的“Hello World!"程序也需要标准库的支持。但你必须小心,不要引入了不需要的东西。
臭名昭著的继承经常带来过多的负担。使用委托代替继承,一般可以获得更高的效率,更多的灵活性,害羞的人不和陌生人说话,同样,害羞的代码也应该避开其他的代码。
如果一段代码在运行的时候使用了其他的代码,就会导致动态耦合。这可能导致严重的问题:就像火车事故,一撞一大串,就像下面的调用。
getOrder().getCustomer().getAddress().getState()
为了得到一个定单的状态,必须知道有Customer,Address和Order对象的存在。这个代码就依赖于这三个对象的组成结构。如果这种组成结构发生了变化,就会导致麻烦。害羞的代码应该只和他直接面对的对象对话。
当
业务的逻辑嵌入到了代码中,就会造成问题域耦合。如果现实世界的业务变化频繁,应该把业务的逻辑放到元数据中,以数据库或文件的方式存放。不要让代码知道
太多的细节。代码实现的是一个引擎,当业务逻辑发生编译的时候,代码可以保持不变。对这种情况,实际中,可以实现一个小的解释执行程序,这种方法非常好
用。
临时耦合,是指代码依赖于时间因素:比如事件
发生必须按照一定的顺序,必须在一定的时间,或者更糟糕,必须在同一时间发生。编码的时候应该总是考虑:代码有可能在并发的环境执行,应该编写线程安全的
代码。这种考虑会有额外的好处,你的设计会更好。你要保持这种思路:你的代码在执行的时候,应该是不受外部任何因素影响。
代码不应该爱管闲事。不要像一个爱管闲事,好说闲话的邻居大妈。
Tell the other guy 通知他,但不要指挥他
我们特别喜欢的一个面向对象的原则:“通知他就行了,不要告诉他如何做”。
因为传统的原因,我们已经习惯使用“函数调用”这个概念来考虑程序设计。甚至在面向对象的系统中,我们也把一个对象的接口看成一组函数。其实,这有着不好的暗示,应该把他看对像直接互相发送的消息,而不是函数调用。
“发
送一个消息”,这种文字营造一种气氛,这种气氛里面,对象彼此之间保持冷漠。我给你发送了一个请求,我才不管你如何做呢。这种请求服务的观点,是产生好代
码的关键。对像之间保持少言寡语的气氛,意味着好的设计。你告诉一个对象,要干什么就行了。千万不要:向他询问细节和请求数据,然后自己来完成处理。
使用这种方法,让你的代码可以不关心不太多的细节。这样,你的代码就容易被修改。要在一个系统中使用这种方法,你应该保持一种思路,总是提供通用的功能:每一个情况下的print调用,都应该是相似的。
这
不是面向对象特有的技术。甚至在脚本中都可以使用这种策略。其实,有一个工具在命令行层次上实现了多态性,fsck是文件系统检查命令,当你调用他的时
候,他会检查文件系统的类型,然后调用对应的程序:fsck.ext2,fsck.msdos,fsck.vfat,
这些程序来完成真正的检查任务。至于你,不需要关心文件系统的类型,你告诉fsck,“干活”, 他就干了。
所以请记住:“keep it DRY, keep it shy and tell the other guy".
阅读(2690) | 评论(2) | 转发(0) |