浅论阴阳太极与 UML 建模

发表于:2007-04-22来源:作者:点击数: 标签:uml浅论nbsp太极阴阳
浅论阴阳太极与 UML 建模 ZX-UDD 的另一个重要组成部分是利用统一建模语言 UML 对 面向对象 软件的设计进行建模,这部分建模当然是 敏捷 的(agile),没有人喜欢笨拙的建模。简单的只需几秒钟可以迅速在人的大脑中完成,复杂的则可以画在纸上、白板上,记录

浅论阴阳太极与 UML 建模


ZX-UDD 的另一个重要组成部分是利用统一建模语言 UML 对面向对象软件的设计进行建模,这部分建模当然是敏捷的(agile),没有人喜欢笨拙的建模。简单的只需几秒钟可以迅速在人的大脑中完成,复杂的则可以画在纸上、白板上,记录在建模工具生成的电子文档中。

软件究竟是什么?有很多比喻可以形容。静态的软件就像一座虚拟的建筑(Architecture),而运动时的软件有时就像一部开动的虚拟机器,或多条柔性的工厂流水线(进程与线程),有时又像一种虚拟的生物,可以肆意地复制和生长(比如软件病毒)。过去有一种说法,认为:程序 = 算法 + 数据结构,如今看来这种旧结构化时代的观点是不准确、不全面的,在新结构化时代我们至少可以得出这样大致的公式:程序 = 算法 + 软件结构 + 数据结构 + ?,在这里我们强调软件结构不同于数据结构,软件是操纵数据的程序,而除了算法和数据结构以外,软件结构(包括架构和设计模式)的质量对软件的质量同样具有决定性的影响。

过去这 15 年无疑是面向对象(OO)软件的天下,世界软件开发早已进入了 OO 时代。人们知道,高质量的好软件是设计出来的,而软件的设计目前依然主要依赖于人们大脑的思考和判断,人类大脑的思考过程恰是一个对现实世界以及虚拟世界建模的过程。而作为 OO 建模技术的事实上工业标准,统一建模语言(UML)正好为我们提供了一个运用 OO 思维进行软件建模和设计的工具。

UML 1.4.2 成为正式国际标准 ISO/IEC 19501,是软件设计史上的一个重要事件,UML 标准成熟之后的研发进展也比较顺利,当前最新版本为 2.1。UML 有什么用?作为一种建模“语言”,促进沟通是一项基本功能,然而很多人忽视了 UML 独立于传统具象编程语言、擅长表达抽象 OO 概念的一大特点。事实上,熟练掌握 UML 能够帮助我们的大脑学会快速、敏捷地 运用 OO 方式进行思考。UML 标准及其相关技术不但是近 10 年来各工程领域 OO 软件设计与建模的利器,还是当前表达软件设计模式最形象和最有效的工具。

在我看来,学会运用 UML 思考,抽象地用 UML 表达软件架构和设计方案,从而能透过现象看本质,是当今世界上任何一名软件架构师乃至普通 OO 程序员都应该尽快掌握的基本功。所以,这几年世界各地的大专院校纷纷把 OOAD/UML 列为一门软件工程专业的必修课也在情理之中了。

建模(modeling)并不是软件行业所特有的做法,建模几乎是几千年来人类所有工程行业所共有的一项最佳实践。为什么我们要对软件建模?因为软件太复杂,难以理解和掌握,我们需要一种能够简单而深刻地反映软件设计本质的方法和工具。如何建模?就像对待建筑模型、机械模型一样,软件也是一个多面体(虚拟的),我们也需要选择视点、视角和视图,对模型做投影、做切片。Philippe Kruchten 博士提出的著名的 4+1 视图(逻辑视图、实现视图、构件视图和进程视图,再加上用例视图)为我们利用 UML 对复杂软件的结构和行为建模提供了很好的指导。

软件设计和 UML 建模既然那么重要,有什么简单易学、提纲携领的好方法、好原则吗?

我曾经编写了一首建模口诀,多次在讲课、咨询时与客户、学员们分享交流,取得了很好的效果。这首太极建模诗(或叫“十六字 OO 建模口诀”)受到了 Craig Larman(《UML和模式应用》)、Alistair Cockburn(《编写有效用例》)、3 Amigos(《UML用户指南》)等世界级专家们睿智大作的启发,也凝结了我 10 多年来从事 OO 设计和编程的一点小小感悟。

太极建模诗

张恂

由外而内,

层次分明。

动静结合,

逐步求精。
The Yin-Yang of Modeling

Craig Larman (Contributor)

Peek from Out to In,

grasp High and Low,

complement Dynamic with Static,

and, unravel the Coarse-grained to the Fine-grained.

我发现“外与内,高与低,静与动,粗与细”等基本二元辩证关系,不但适用于软件用例需求的建模,也适用于软件架构的 OOAD/UML 建模。当然,软件设计中的二元关系还远不止这些。充满了二元辩证、平衡之道的现代软件工程,竟然与两千年前中国古典哲学《阴阳太极》中的黑、白对立统一相暗合,这真的是历史的巧合,还是科学的必然?

由外而内


外与内,即软件系统本身与其外部环境的关系,大概是软件开发中最根本的一对关系。在软件开发之初需求调研时,我们通常视整个软件系统为一个黑盒子,我们划地为界,从系统外部来观察软件提供给其各个用户的功能,以及它与外部环境的各种动态关系(包括彼此之间的行为交互和信息数据的交换)。这种方法可以用 UML 用例图表示如下:

以银行证券帐户管理系统(类似于“银证通”)为例,图中用例“打印帐户报告!”的需求简述是:

主用角:用户
辅用角:外汇交易中心、证券交易所
范围:证券账户管理系统
层次:用户目标层
后置条件:
    系统打印客户帐号下已购买的所有币种的证券清单,包括每支证券的单价、份数、余额以及该客户账户下的资产总额(转换成用户指定的币种,缺省情况下为美元)。  系统打印客户帐号下已购买的所有币种的证券清单,包括每支证券的单价、份数、余额以及该客户账户下的资产总额(转换成用户指定的币种,缺省情况下为美元)。
前置条件:
    用户已登录,客户的账户、帐号已知。  用户已登录,客户的账户、帐号已知。
触发事件:
    用户选择打印账户报告(证券余额清单)。  用户选择打印账户报告(证券余额清单)。
基本流:
    1. 用户根据系统提示选择结算币种(用于计算资产总额),缺省值为美元。  1. 用户根据系统提示选择结算币种(用于计算资产总额),缺省值为美元。
    2. 系统读取该客户帐号下的所有证券信息,打印每支证券的名称、份数、单价和总价(即证券余额,等于单价 * 份数),总价用原币种表示。  2. 系统读取该客户帐号下的所有证券信息,打印每支证券的名称、份数、单价和总价(即证券余额,等于单价 * 份数),总价用原币种表示。
    3. 系统根据该账户下的证券币种读取相应的结算汇率,把所有证券余额都统一转换成结算币种,并通过累加该账户下所有证券的余额,计算出以结算币种表示的客户资产总额并打印输出。  3. 系统根据该账户下的证券币种读取相应的结算汇率,把所有证券余额都统一转换成结算币种,并通过累加该账户下所有证券的余额,计算出以结算币种表示的客户资产总额并打印输出。
扩展流:
    2a. 系统读取证券信息(份数、价格)失败:  2a. 系统读取证券信息(份数、价格)失败:
        2a1. 系统报错,用例结束。  2a1. 系统报错,用例结束。
    3a. 系统读取汇率失败(某支证券的币种到结算币种的转换汇率不存在):  3a. 系统读取汇率失败(某支证券的币种到结算币种的转换汇率不存在):
        3a1. 系统告知用户结算汇率不存在,无法计算资产总额,用例结束。  3a1. 系统告知用户结算汇率不存在,无法计算资产总额,用例结束。

明确需求后,当我们打开软件系统这只盒子,进入它的内部,把盒子内的一切东西、机关要害都搞清楚、弄明白,也就完成了软件开发从需求,到分析,到设计,到编程实现的这么一个过程,而我们最终送给客户的必须是一个高质量的大礼包。

那么,这只盒子内部有何宝物呢?由外而内,由大而小,一个软件分别由系统,子系统(subsystem)与构件(component),以及对象组成。一个系统由一个或多个子系统组成,而一个子系统可以由一个或更多的子系统(或构件)组成。构件里面装的则是对象,对象又由属性和方法(即通常所说的函数)组成。类(对象)正是现代软件的最小组成单元,就像组成有机人体的基本单元 —— 细胞。下图用 UML 包图表现了这样一种软件系统的嵌套解剖视图。

层次分明


“分而治之”是工程界对付复杂技术问题最常用的手段。作为一个复杂的系统,软件也不例外,清晰而严谨分层的结构往往是优秀软件设计的一个主要特征。

分层有横切、纵切两种。软件设计从系统,到子系统和构件,再到类与对象,再到类的内部属性和方法,以及某个方法的编程实现,既是由外而内,也是从高到低,从高层的架构设计(系统、子系统),到低层的类与类的关系、类内部的设计,就像山脉与山峰、森林与树叶的关系。对应着这样的高、低层关系,在软件设计中,目前世界上已有大量的架构模式、设计模式、实现模式和各种分层的框架可供我们借鉴、重用。

以上谈的是软件内部的分层。再举一个软件外部需求分层的例子。同样用 UML 用例图表示:

该图说明在软件的外部,软件需求也是可以分层的。“预定酒店!”和“购买机票!”是用户使用软件的真正目标,属核心用例,而特性“显示宾馆列表-”、“保存客户信息-”、“可用航班排序-”等当然也是需求,但它们不过是更高层的需求 —— 用例当中的一个步骤。我们用 Cockburn 推荐的 “!”、“-” 等符号表示这些需求在层次粒度上的区别。

动静结合


经常有初学者问:用 UML 建模的时候,我们到底要画几张图才算表达完整,哪些图最重要?其实有一个非常简单的回答:动静结合。

客观世界是由物质(如微观粒子)组成的,而物质是运动的。巧合的是,软件这个虚拟世界也不例外。因此在我们设计软件的时候,既要说明有哪些“虚拟”物质(如构件、对象、属性等)存在,也不要忘了描述物质之间的运动(如交互、状态变迁等),两者是相辅相成的。

以下我们展现了参与“打印帐户报告!”用例实现的主要对象之间,为了完成这一功能所结成的静态关系(用 UML 类图表示)和动态关系(我们选择了 UML 协作图)。





事实上,只有细致考虑了对象之间的静态和动态关系(不管利用何种媒介,大脑抑或文档),我们的软件设计才算是完整的,编程才有正确的依据。不然,您的程序代码从何而来?

逐步求精


软件开发从软件的需求(问题域)到可执行的高级程序设计语言源代码(解决域),这中间究竟经历了多少思考步骤和权衡过程?是一步到位吗?实际上 1)宏观地从软件需求,到代码实现 2)软件设计中的从分析对象,到设计对象,再到实现对象,或者从设计模式到模式的编程实现,这些都是一个逐步求精的过程。

...

小结


UML 建模对于软件设计的重要性,对于一名老练的 OO 程序员来说,是不言而喻的。UML 那抽象、简洁、高于 JavaC++ 诸等高级程序设计语言之上的形象表达,可以让我们真切领略到蕴藏于软件那纷繁芜杂的细节表面之后的一份简单、和谐之美。

UML 作为一种图形化建模语言规范,凝聚了世界上许多大师级 OO 建模、设计专家多年来的宝贵经验,它的表达手段异常灵活和丰富,面对 UML 2.x 十几种图符,我们该如何运用?期望我与 Craig Larman 大师合作的《太极建模诗》能给读者朋友们带来一些有效的帮助,happy modeling !

原文转自:http://www.ltesting.net