软件工程好对象的7大美德

MarinFolwer说过:“库本质上是一组可以调用的函数,这些函数现在经常被组织到类中。”

函数组织到类中?恕我冒昧,这个观点是错误的。而且这是对面向对象编程中类的非常普遍的误解。类不是函数的组织者,对象也不是数据结构。

那么什么是“合理的”对象呢?哪些不合理呢?区别又是什么?虽然这是个争论比较激烈的主题,但同时也是非常重要的。如果我们不了解对象到底是什么,我们怎么才能编写出面向对象的软件呢?好吧,幸亏Java、Ruby,还有其他语言,我们可以。但是它到底有多好呢?很不幸,这不是精确的科学,而且有很多不同的观点。下面是我认为一个良好对象应该具有的品质。

类与对象

在我们谈论对象之前,我们先来看看类是什么。类是对象出生(也叫实例化)的地方。类的主要职责是根据需要创建新对象,以及当它们不再被使用时销毁它们。类知道它的孩子长什么样、如何表现。换言之,类知道它们遵循的合约(contract)。

有时我听到类被称作“对象模板”(比如,Wikipedia就这样说)。这个定义是不对的,因为它把类放到了被动的境地。这个定义假设有人先取得一个模板,然后使用这个模板创建一个对象。技术上这可能是对的,但是在概念上是错误的。其他人不应该牵涉进来—应该只有类和它的孩子。一个对象请求类创建另一个对象,然后类创建了一个对象;就是这样。Ruby表达这个概念要比Java或C++好多了:

1photo=File.new(/tmp/photo.png)

photo对象被类File创建(new是类的入口点)。一旦被创建后,对象可以自我支配。它不应该知道是谁创建了它,以及类中它的兄弟姐妹有多少。是的,我的意思是反射(reflection)是个可怕的观点,我将会在接下来用一篇博客来详细阐述:)现在,我们来谈谈对象以及它们最好和最糟的方面。

1.他存在于现实生活中

首先,对象是一个活着的有机体。而且,对象应该被人格化,即,被当做人一样对待(或者宠物,如果你更喜欢宠物的话)。根本上说,我的意思是对象不是一个数据结构或者一组函数的集合。相反,它是一个独立的实体,有自己的生命周期,自己的行为,自己的习惯。

一名雇员,一个部门,一个HTTP请求,MySQL中的一张表,文件的一行,或者文件本身都是合理的对象—因为它们存在于现实生活,即使当软件被关闭时。更准确来说,一个对象是现实生活中一个生物的表示(representative)。与其他对象来一样,它作为现实生活中生物的代理。如果没有这样的生物,显然不存在这样的对象。

1photo=File.new(/tmp/photo.png)putsphoto.width()

这个例子中,我请求File创建一个新对象photo,它将是磁盘上一个真实文件的表示。你也许会说文件也是虚拟的东西,只有电脑开机时才会存在。我同意,那么我把“现实生活”的重新定义为:它是对象所处的程序范围之外的一切事物。磁盘上的文件在我们的程序范围之外;这就是为何在程序内创建它的表示是完全正确的。

一个控制器,一个解析器,一个过滤器,一个验证器,一个服务定位器,一个单例,或者一个工厂都不是良好对象(是的,多数GoF模式都是反模式(anti-patterns)!)。脱离了软件,它们并不存在于现实生活中。它们被创建完全是为了将其他对象联系在一起。它们是人造的、仿冒的生物。它们并不表示任何人。严格上说,一个XML解析器到底表示谁呢?没有人。

它们中的一些如果改变名字可能变成良好的;其余对象的存在则是毫无理由的。比如,XML解析器可以更名为“可解析的XML”,然后可以表示我们程序范围外的XML文档。

始终问问自己,“我的对象所对应现实生活中的实体是什么?”如果你不能找到答案,考虑下重构吧。

.他根据合约办事

一个良好对象总是根据合约(constract)办事。他期望被雇佣是因为他遵循合约而不是他的个人优点。另一方面,当我们雇佣一个对象,我们不应该歧视它,并期望一个特定类的特定对象来为我们工作。我们应该期望任何对象做我们间的合约所约定的事情。只要这个对象做我们所需要的事,我们就不应该关心他的出身,他的性别,或者他的信仰。

比如,我想要在屏幕上展示一张图片。我希望图片从一个PNG格式的文件读取。我其实是在雇佣一个来自DataFile类的对象,要求他给我那幅图片的二进制内容。

但是等会,我关心内容到底来自哪里吗—磁盘上的文件,或者HTTP请求,或者可能Dropbox中的一个文档?事实上,我不关心。我所关心的是有对象给我PNG内容的字节数组。所以,我的合约是这样的:

13interfaceBinary{byte[]read();}

现在,任何类的任何对象(不仅仅是DataFile)都可以为我工作。如果他是合格的,那么他所应该做的,就是遵循合约—通过实现Binary接口。

规则很简单:良好对象的每个公共方法都应该实现接口中对应的方法。如果你的对象有公共方法没有实现任何接口,那么他被设计得很糟糕。

这里有两个实际原因。首先,一个没有合约的对象不能在单元测试中进行模拟(mock)。另外,无合约的对象不能通过装饰(decoration)来扩展。

3.他是独特的

一个良好对象应当总是封装一些东西以保持独特性。如果没有可以封装的东西,这个对象可能有完全一样的复制品(克隆),我认为这是糟糕的。下面是一个可能有克隆的糟糕对象的例子:

classHTTPStatusimplementsStatus{privateURLpage=newURL(







































鍖椾含鍘诲摢瀹跺尰闄㈡不鐤楃櫧鐧滈鏈濂?
鐧界櫆椋庡尰闄㈣タ瀹佸摢瀹跺ソ



转载请注明地址:http://www.henanledxianshiping.com/rjkf/3723.html
  • 上一篇文章:
  • 下一篇文章: