Kingonion 2010-06-03
面向对象更是一种方法论,而不仅仅是一种技术。掌握一种技术可以解决某一特定问题,掌握一种方法却可以随机应变、因势利导、因地制宜。就像张无忌学习太极拳,招式忘记的越多,拳中的圆转不断之意领会的越深,所能解决的问题域就越阔,威力也就越大。
如何去看决定了看到了什么。面向对象也是如此。从技术实现角度看,对象就是拥有方法的数据,就是属性和方法的结合。在这种思维的指导下,构建对象就变成了去搜集属性和方法;凡遇一对象,必对该对象的属性、方法勾勒一番;见一人,则心里想着身高、体重、性别、姓名、能跑、能跳;这么做,过早的涉及到了实现细节,这和创建数据库中的一张表有何区别。而且,过早的想当然的规定属性、方法有可能是不正确的;比如人,这个对象在不同的问题域中所扮演的角色不同,虽然人作为一种生物是有性别的,但这个人如果是一位电话接线员,则他(她)的性别则是无关紧要的。此时在人这个对象里加一个性别属性是冗余的。
从更高的层次看对象,对象是拥有一个或若干职责的实体。这是说我们要把注意力放在对象是用来干什么的,而不是把注意力放在对象是如何实现的。先要知道做什么,然后再去考虑怎么做。目标在先,行动在后。先有一个概念上(conceptual)的对象,再有对象的实现。总之,它是在教我们思考问题的两步法,1,whattodo?2,howtodo?如是而已。如各位所想,这种思考问题的方法也司空见惯、稀松平常,除了软件设计领域外,其他领域又何尝不是如此。人的思维就像溪流,注意力就像小船,有时随波逐流,不知不觉陷入细枝末节,不能自拔。如果有意识的提醒用这两步法去重新认识问题,则可避免使自己在设计上误入歧途。而以职责的角度看对象,让你跳出画外看画。Makeityourbasicviewpointforobjects.Ifyoudo,youwillhavesuperiordesigns.(让它变成你分析对象的基本方式,这样,你定会拥有上佳设计)。
面向对象中的封装是对数据的一种隐藏。而这只是技术层面上所展示的封装思想微不足道的一部分而已。封装实际上是教我们看待问题的一种方法,这种方法就是整体法,而用整体法分析问题,自从有人类出现就一直在使用。封装这个概念,只是这种思想在软件开发领域另一种表述。当你从整体上来考虑一个模块时,你就正在对这个模块进行封装。模块中的细节对你来说是一个黑箱,你只关心它的整体表现。实际上,如果你不用整体法来分析一个系统,你几乎无法对系统进行拆分。面向对象技术只是顺应了这种人类思考的习惯。所以,从这个意义上来说,面向对象是简单的和容易掌握的。
软件系统中,需求永远在变。面向对象技术在捕捉需求变化的方式之一就是封装变化的部分。如果你以前一直把封装简单的看作是一种数据隐藏,那么就不好理解什么是对变化进行封装。对变化的封装,就是对不确定因素的隔离。Win32的回调函数就是一种对变化的隔离,系统调用你(用户写的被系统调用的函数),而不是你调用系统。你是不确定的,系统事先并不知道你这个函数里面会执行什么操作,因为你是变化的,是程序员根据不同的用户需要后天写就的。抽象类也是一种对变化的隔离、对变化的封装。当然你也可以像通常那样把抽象类理解成Object的分门别类,然后用is-a关系来创建子类。但对于设计者来说,正因为他(她)不知道会有多少种这样的子类存在,所以才使用抽象类来对这种不确定性进行封装。如果明确知道有几个这样的子类存在,并且将来不会扩展(扩展性也是一种不确定性的表现),又何必使用抽象类这种在此情况下多此一举的机制的?
是的,这里没有谈及多态,因为多态只是一种技术手段,它的目的正是把做什么和怎么做隔离、不变和变化隔离。传统结构化分析方法中的功能分解就缺乏这种隔离,一旦需求变化而去做代码修改,修改了一处功能或数据往往可能会影响另一处功能,而赶忙跑去对另一处功能进行修改却沮丧的发现该处修改还影响着第三个地方,如此疲于奔命,到最后绝望的发现bug就像个雪球,越滚越大,目睹此景,不免一时觉得心力憔悴,吐血而亡。
更大尺度的封装就形成分层结构。分层隔离变化,隐藏细节,层与层直接通过接口或协议相互协作沟通,层层推演,形成架构。实际软件架构和公司架构、社会架构实无区别!宇宙是向着效率高的方向演进、社会如此、公司如此、软件设计也如是。封装、分层、以及由此引起的分工、协作极大提高了系统运作效率。
(封装、抽象、信息隐藏可以说是一个问题的三个侧面,也可以说它们是同一回事。抽象的过程自然伴随着封装和信息隐藏,封装的同时肯定也就是在进行抽象思考,这种整体思考法自然会不拘小节(信息隐藏))。