在软件实践中,当专注于某个具体场景下的设计时,我们当中的不少人,很少有时间顾及或者愿意顾及自己思维中更深层次的东西。而当结束设计之后,如果我们因为累日的操劳,想急于放松一下的话,那么等回过头来,再试图做些总结的时候,却发现自己对那些具体实践环节的印象已经变得模糊不清了。而这些细节却很有可能是某个极有价值的思想的源泉。这就像是一个人匆匆忙忙走了一段路,然后停下来歇了一会儿,等他站起身来再回头看时,却已经忘了来时的路了。很遗憾,笔者也属于这样的人。本文试图在做一些对“往事”的回忆,并希望能够由此引发大家的思考。
我们看到了什么?
当我们站在高处眺望远处的楼群时,也许我们无法看清这些高大建筑的每个细节,门窗的制式、所用的型材……,可是我们却由此看清了它们的总体结构和趋势。在一个OO系统里,亦是如此,当我们忽略具体细节,以同样的目光审视这些OO世界里的建筑物时,我们看到了什么?我想,我们所看到的多半是一系列对象,以及介于这些对象之间的关系。
在清楚认识了呈现在我们面前的总体结构和趋势之后,后续问题便接踵而至。
我们在做些什么?
从上述观点出发,我们的设计过程便等同于:勾画各个对象自身,明确其责任;安排对象之间的关系,使其构成一个整体。在这个问题上,尽管有诸多方法,但无一例外的是,所有方法都在做着这件相同的事情。
在明白了我们的行为所针对的对象和行为本身的含义之后,问题又产生了。
我们的目标是什么?
还有几个相关的问题:如何评价我们的行为(即评价标准问题)?我们所做的是好是坏?要做到什么程度?如果我们将目标作为评价标准,那么这些问题事实上可以归并为同一个。至于评价标准,在没有完成设计之前,我们大可以对此提出苛刻的、近乎完美的目标,而且,有很多这样的候选项可供选用。但是,正如Kent Beck所说的:
“Program have two kinds of value:what they can do for you today and what they can do for you tomorrow.”
诸多标准,最后可以分为两类:正确完整地实现既定功能;保证能够让后续开发顺利进行。当一个OO设计(也就是我们行为的结果),没有实现现有的需求,勿庸置疑,那自然是失败的,是一个不良设计。而在我们解决了“温饱问题”之后,我们就有机会可以将眼光放得更长远一些了,我们开始考虑如何使系统的结构更合理、更精巧;如何使之易于移植、易于复用;对于变化的需求,如何使之表现出更大的弹性;并开始考虑效率和成本的问题。理想状况下,我们的思考顺序是这样的,即我们首先考虑第一类评价标准,然后再考虑第二类,两者偶有交叉。但事实往往是,我们很容易会把这两者混在一起,而且越是优秀的programmer,就越可能犯这样的毛病(所以一个好的programmer,未必是一个好的designer)。
行为的对象、行为本身、行为的目标都有了,似乎所有关于认识的问题都明确了,这就剩最后一个,也是最具吸引力、最值得探索的问题了。
我们该如何去做?
如果把这些论述和哲学做个类比,那么前面所讲的大概属于本体论范畴,而这里所提的应该属于方法论范畴。有很多可以选用的方法,比较新的有:设计模式(Design Pattern),代码重构(Refactoring)。还有一些传统的面向对象设计方法,当然还有Quick and Dirty。对于不同的场景,目标的选取(既评价标准的选取)可能是有侧重的,这就有了选择不同方法的依据。某种方法并非在任何时候都是最适合的。它取决于你优先选用了诸多评价标准中的哪几个。有时,这些标准往往是彼此矛盾的,所以你不得不在它们中间不断的做折衷,寻求平衡点。最大的一对矛盾存在于上述两类评价标准之间,另一对在某些场合下很常见的矛盾,则是“结构和效率”(比如面向嵌入式系统的应用)。
小结
在认识了上述四个基本问题之后,我们看到了一个存在于OO世界里的框架,一个自封闭的、逻辑上完整的概念框架。每个问题(环节)彼此互不重复,又前后相继。在OO的世界里,每个“对象”(包括事物、概念、方法等等),都可以被归并到上述某个环节中,它们之间彼此又有着逻辑上的关联。每天,我们就是在这样的一个框架里做着我们该做的事情。
个人观点,仅供参考。