命名与抽象

好的名字总是能为代码的可读性做出重大贡献,而这种贡献是通过对事物进行抽象实现的。

想想一下我们平常说话时所用的语言,比如说“我家的狗跑的很快”,“家”、“狗”和“跑”都是抽象,它们分别代表了不同的含义,如果不适用这几个抽 象的词汇,而是直接说它后面所代表的含义,恐怕几十句话都说不完。不信的话,你可以试试定义一下什么是狗,什么是跑,保证不是那么容易的事。

抽象可以说是软件设计和开发中的核心概念,对变量、方法、类、接口、包等元素的命名,都包含了抽象过程。例如方法,方法的名字应等价于方法内部所有 代码的功能,也就是说方法的名字是方法内代码功能的抽象。于是,不管是在交流还是记忆上,我们都可以使用方法名来指代它内部的功能。

由于人的记忆力和理解能力都是有限的,据研究称,人最多之能同时处理7个左右的事物。因此对于复杂的软件系统,抽象就成为让人能够理解的重要手段。 在代码量较小的系统中,可能抽象也比较少,理解起来比较容易,变量、方法和类基本就能处理了;而在大一些的系统中,由于抽象较多,因此需要更多的抽象层 次,使得在每一个抽象层次上都能有比较少的抽象概念,以利于理解,于是出现了诸如分层、子系统、组件、库等等。同时在类和方法内部,也会有分层次的抽象, 继承就是类的一个抽象层次关系,而方法之中调用其它方法,也是抽象层次的一种表现。

例如,狗这个类可以有很多不同子类,每一种代表不同品种的狗。从上往下看,子类是父类的泛化,是在父类上添加更多的细节;而从下往上看,父类则是子 类的抽象,集合了更多子类的相同之处。在类的层次结构中,每一级的父类都会包含更多的抽象和更少的细节。因此往往父类比子类更能表达这个层次结构的核心概 念,也就应该更谨慎的选择一个好的名字,来表达这种核心概念。同时子类的名字应该能够体现它的子类的共性,同时还应能够区分与其它同级子类的不同。

而在方法中,我们有一种使方法更具可读性的方式,就是让方法中的每一行代码都处于相同的抽象级别。例如,“我家的那只会叫的哺乳类四腿……动物跑的 很快”这句话就很难理解,因为你的思维需要在不同的抽象级别上跳来跳去,“家”和“跑”都是可以马上理解的概念,而“会叫的哺乳类四腿……动物”则是需要 思考一下才能理解的。因此比较简单的做法就是将这个细节抽象称一个名字“狗”,将之提取出来,形成另一个概念(也就是方法)。于是,系统中的方法本身也就 有了不同的抽象层次,有些关注与调用语言和平台的API来实现某些操作,有些则会调用这些方法实现更高层次的逻辑。在面向过程的设计中,最后的结果就是 main函数,而在OO设计中,可能是某个类的public方法。

命名好坏对可读性的影响,实际上是抽象方式对人的思维方式造成的影响。如果你找不到一个好的名字,通常就意味着你对问题的抽象是不恰当的,隐含的意思就是你对问题的理解不够深入或者理解错误。

--------------------------------------------------------------------------------------------------------------------------------------

添加示例代码:

原来的代码

Code


现在的代码:
Code

可以看到,原来的代码中,start方法有很多行,有些行做得是一件事,可以抽象出方法,提取出的方法又可以组合成一些类,这样每个类、每个方法都比较短,且方法中的代码处于同一抽象级别。
比如这个方法
Addon.prototype.open = function(url)
{
  
this.htmlWindow.newTab(url);
}
只含有一行代码,但是形成方法之后,open就代表了抽象出来的动作open url,而这一行代码只是实现这个动作的细节。这样,不仅可以很容易的替换实现细节,而且还能够重用这个抽象动作。

再看这个方法
function handleException(exception)
{
   alert(exception);
}
handleException这个名字反映了我们的意图是要处理这个异常,而目前处理的方式是alert一下。但是如果不要这个方法,直接把alert内联到调用函数中,就很难表明alert是一种处理异常的方式,而不是调试或者做别的事情。
posted @ 2009-09-17 11:35 Nick Wang (懒人王) 阅读(...) 评论(...) 编辑 收藏