开发者社区> 异步社区> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

《UML面向对象设计基础》—第1章1.9节一般性

简介:
+关注继续查看

本节书摘来自异步社区《UML面向对象设计基础》一书中的第1章1.9节一般性,作者【美】Meliir Page-Jones,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.9 一般性
UML面向对象设计基础
一般性(genericity)指一个或多个类内部使用的类C的结构,仅在运行时(即示例类C的对象时)才提供。

说明一般概念的最好方式是讲述一个不堪回首的故事。当时我还是一名大学生,学习一门数据结构(Data Structures)的课程101。有一个学期,Rossini 教授给我们留了一项作业,设计和编程整数有序平衡二叉树(见图1.22)。平衡二叉树的主要特点是所有的叶子在同层上拉平。


47a0f119ed714001116858facdd7c37f5b60877e

在往树中插入另一个整数(如5 ,见图1.23)之前,一切顺利。插入整数5后,树变得不平衡,你不得不做一些痛苦的节点调整直到树再次平衡为止。

923d844ac61492b7a9b82a166cb6260de5df4aca

经过多次的桌面设计和联机调试,我们中间大多数人的算法可以正常运行了。带着满意的笑容交出程序去度假,花费几夜的努力去忘却那个有序平衡二叉树。

但不幸的是,Rossini教授的平衡树作业进一步扩大范围。作为下学期应用的一部分(商业应用101,Business Applications 101),需要将客户和产品形成排序列表。我们这些学习Data Structures 101的学生,还没有完全忘记有序平衡二叉树,径直调出老程序,复制二份。在一份副本中,用CustomerID替换Integer;在另一份副本中,用ProductID替换Integer。

这种对老程序的复制极大地提高了生产率。但这种方法并非十分理想,因为存在严重的复制隐患。这种隐患是现在我们不得不维护三个几乎相同的程序。

因此,如果我们发现了一个更好的平衡树算法,就不得不修改三个代码。这样不仅增加了额外的工作量,而且维护三个版本也有一定的难度(除非我们有自动的复制修改程序)。我们需要一种方法,只编写一次基本的平衡树算法结构,然后当我们需要对整数、客户、产品或其他进行处理时可以应用多次(不是简单的复制)。

此时此刻,一般性就像一匹疾驶而来的白马拯救了我们。如果将BalancedTree 定义为参数化类(正规称为一般类),则说明至少在BalancedTree中有一个类直到运行时才赋值(参数化类在C++中称为模板类)。可以猜到这个类就是我们实例化时,存储在特定平衡二叉树对象的节点中项所构成的类。

因此可以将类BalancedTree写为如下形式:

class BalancedTree<ClassOfNodeItem>;

 …

 var currentNode:ClassOfNodeItem.New;

 …

 currentNode.print;

 …

注意参数化类的参数ClassOfNodeItem。这是一个形式参数,其实际“值”在运行时提供。例如,当实例化类BalancedTree的一个新对象时,将提供一个真正的类名作为参数,如:

…

var custTree:BalancedTree :=BalancedTree.New<Customer>;

var prodTree:BalancedTree :=BalancedTree.New<Product>;

…

因此,custTree现在表示一个在节点中保存类Customer实例的对象(即BalancedTree的实例),如图1.24所示。当然对于prodTree是类似的。


057016f555a47060b925b04f522b7018ac246612

下面的程序看起来好像将第一段程序复制了两次(一次是为Customer,一次是为Product):
class BalancedCustomerTree;

  …

  var currentNode:Customer:=Customer.New;

  … 

  currentNode.print;

  …

 class BalancedProductTree;

  …

  var currentNode:Product:=Product.New;

  … 

  currentNode.print;

  …

最后,注意currentNode.print语句。这是多态的一个好例子,因为当我们在参数化类BalancedTree中写这个语句时还不知道currentNode的类是什么。因此,实例化BalancedTree时操作print应根据用于实例化特定树的类而定义。

另举一个例子,如果你设计一个参数化类HashTable,则应指出任何向C提供实际参数的类(如Symbol)必须定义操作hash 。在第12章详细讨论一般性可能带来的危险。

你可能意识到一种不用一般性也不用复制编写BalancedTree的方法。可以让平衡树的节点接受一个超类/子类层次结构中最顶层的类对象。如果将该类命名为类Object,则该代码段为:

class BalancedTree;

  …

  var currentNode:Object:=Object.New;

  … 

  currentNode.print;

  …

现在平衡树的每个节点将接受任何一个对象的加入。甚至可以将客户、整数、产品、多边形、牛仔及马混在相同的树中。这几乎没有什么意义。更糟的是让这些不同的对象类理解消息print是不太可能的。

BalancedTree和HashTable都是容器类(container class)的例子。容器类用在某些(通常比较复杂)结构中保存对象。一般性常用在面向对象中设计这样的容器类。尽管不是必须使用一般性为容器类编写可重用代码,但它确实比复制的程序或将任意类的对象混合在同一个容器的脆弱设计要好。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
《面向对象设计实践指南:Ruby语言描述》—第1章 1.5节小结
如果某个应用程序存活了很长时间(也就是说,如果它成功了),那么它最大的问题将是如何应对变化。通过代码编排有效地应对变化是设计的事情。最常见的设计要素是原则和模式。不幸的是,即使正确地运用了原则,并且也恰当地使用了模式,也无法保证能够很好地创建出易于更改的应用程序。
1410 0
《面向对象设计实践指南:Ruby语言描述》—第1章 1.1节设计赞歌
世界是过程式的。时间不停在向前流动,而事件也一个接一个地逝去。你每天早上的过程或许就是:起床、刷牙、煮咖啡、穿衣,然后上班。这些活动都可以使用过程软件来建模。因为了解事件的顺序,所以你可以编写代码来完成每一件事情,然后仔细地将这些事情一个接一个地串在一起。
1603 0
《面向对象设计实践指南:Ruby语言描述》—第8章 8.1节组合对象
本章会对OO组合技术进行讲解。在开始时举了一个示例,接着会对组合与继承的相对优缺点进行讨论,然后得出如何选择替代设计技术的建议作为结论。
1319 0
+关注
异步社区
异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。
12049
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载