天天看点

《基于模型的软件开发》——3.1 泛化

本节书摘来自华章计算机《基于模型的软件开发》一书中的第3章,第3.1节,作者:[美]h. s.莱曼(h. s. lahman)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

泛化是对集合论的一种基本应用。回忆一下,在第2章中,我们将类定义为一个实体集合,这些实体都具有相同的属性。集合论中有子集的概念,如图3-1所示。该图称为维恩图,其中的点表示集合的成员,而实线标识出集合的边界。图3-1是一个有关银行账户的维恩图示例。图中的点表示银行客户所拥有的独立银行账户。在这个例子中,银行账户必须是支票账户或者储蓄账户,而不能既是支票账户又是储蓄账户。方框表示了各类银行账户的边界:外层的方框表示的是所有银行账户的集合,称为超集,内部的方框表示的是支票账户和储蓄账户两个子集。我们还可以在其中增加其他的子集,例如个人退休金账户。

《基于模型的软件开发》——3.1 泛化

图3-1 一个银行账户维恩图的例子:账户的全集可以划分为特定的独立的组——支票账户和储蓄账户

每一个点表示了所在子集边界之内的一个唯一可标识的成员。在这个例子中,账户通过账户拥有者和账户类型的组合来进行唯一标识。注意,同一名客户同时拥有支票账户和存储账户的可能性是存在的,因此我们不能仅仅通过用户信息来标识两种账户。

我们来看在支票账户子集中某个给定的点,这个点同样也包含在整个账户集合中。因此可以说这个实体是支票集合的成员,同时也是账户集合的成员。如果我们用“a”来概括表示“集合a的成员”,用“b”来概括表示“集合b的成员”,那么当只有一个点,并且它同时包含在两个集合之中时,我们可以认为b是a。在ooa/d的文献中可以看到泛化是一种“是一个”的关系。这即是它的含义。在维恩图中,任何一个给定的点都表示了单个包含在多个集合中的实体。因此我们可以说该实体是b,也是a。

第2章还提到了类是通过一组职责来定义的。在维恩图中,我们可以很容易地标记单独的集合,但是如果同时尝试在图中枚举定义该特定集合的那些特定职责,将会使图变得很混乱。在面向对象范式中,我们更关心这些职责,因为我们需要通过它们来解决手头的问题。因此我们需要另外一种表示法,如图3-2所示,每一个方框表示与图3-1中相同的集合,但是在集合中枚举属性来替代图3-2中那些实际的点。

《基于模型的软件开发》——3.1 泛化

图3-2 账户子集的面向对象泛化,使用不同的属性定义每个集合。账户的属性被每一位成员共享,支票子集定义了同时拥有“透支账户”属性的账户成员构成的子集。需要注意的是,储蓄账户包括了所有没有其他属性的账户成员

连接类的实线表示了一种泛化关系,其中账户是全集(看做根超类),而支票、储蓄和个人退休金账户是子集类,只包括了账户集合成员的一个子集。维恩图中的点没有必要表现出来,因为特定的连接符已经告诉了我们,我们在看的就是一张维恩图,同时我们也可以推断出子类中的成员也是其父超类中的成员。

请注意,我们已经识别出的属性定义了账户集合。如何协调这些属性与我们用来定义子集的属性呢?很简单。泛化(树状维恩图)中的每一个实体都是账户集合的成员。由于账户集合由其所有成员的共享属性所定义,因此账户集合中的所有实体必须具有这些属性。同样,支票集合中的成员必须具有支票集合定义的属性,还要具有账户集合为其成员定义的属性。支票集合中的成员同时也是账户集合中的成员,因此它必须具有两个集合定义的全部属性。

泛化这个词语来自以下概念:账户集定义了其所有后代子集合中所有实体一般或共同的属性。在oo的上下文中,另一种常见的术语为专业化。专业化捕获账户集合中拥有独特的、特殊的属性的子集,这些属性不是账户集中所有成员都具有的。你现在了解了有关oo泛化的所有内容,这是有关集合和子集合的一种非常简单的组织结构,在uml中表示为树形的维恩图。

在ooa/d文献中,泛化难以捉摸的地方在于它在问题域抽象中的解释。例如,你可能发现在上述解释中我们没有提及“对象”这个词。因为在抽象为一个oo的解决方案之前,泛化必须存在于问题域的实体之间。一种常见的ooa错误是,在解决方案中使用泛化仅仅是因为它很优雅,而且使得建模更加简单。第12章将更加详细地继续讨论这个话题。