首页 > 代码库 > 采用[ICONIX] 方法实践分析和设计之一 [问题域建模](转)
采用[ICONIX] 方法实践分析和设计之一 [问题域建模](转)
前言:自从加入 Discuz!NT开发小组开始。我就放弃了以前的软件设计思想,转而去使用项目组所规范使
用的架构设计思想和开发模式来进行开发。这样的时间一直持续到了今天。虽然我向往面向对象的开发方式,
且向来对不够OO的设计存有偏见。但人必定要生存,特别是已经做了父亲的程序员来说,这种压力是不容回避
的。
但今天开始的这一系列的文章将会说是一次对OO的一种回归。也可以说是对已有的设计思想的一种思考。
在我从这中书柜上拿出这本已有两年多没再看的“用例驱动的UML对象建模应用--实例分析”(Applying
Use Case Driven Object Modeling With UML)之后,一种写OO设计文章的冲动便油然而生。而采用
什么方式去描述一个产品或例子给大家呢?虽然我可以把以前自己所从事的项目或网站设计拿出来与大家一起分
享,但那些示例往往都有一定的局限性,特别是有的项目对没有一定行业背景的人来说是很费解的。
在思考了相当长的一段时间(大约1 个月)后,才发现最好的例子其实就在身边,那就是BLOG,即然大家都在
用BLOG,并且博客园也是BLOG形式,而同时自己也开发过这类的软件(这里献丑了)。所幸就以这个为例子,讲
解用ICONIX方法来进行Blog设计:)
另外最近写手头上的剩余时间也越来越短,好多文章的内容都是在拥挤的城铁车厢中构想完成的。所以这
个系列的文章可能会出来的慢一些,当然本人对所写内容的再三斟酌也是降低写作速度的重要原因 (因为担心
误导大家)。
同时为了不让大家过于沉迷在具体的需求之中, 而忽略这个方法的具体操作流程,我采用直接分析核心功
能和需求(忽略次要需求)。只对系统的核心功能进行建模的方式来介绍这种方法的特性。 (而次要的需求用绿
色标注)这一点希望大家谅解:(
还有需要声明的是文章中出现的任何设计都只是一种思考或假设(仅属个人观点)。因为只有这样才能将我
想到的全部表达出来。因此这里所谓BLOG只是一个供大家交流 UML(OO)设计思想的平台和研究的示例,
我有理由相信肯定会有园子里潜水的高手看到这样一篇陋文而在背地里暗笑的。
但是作为软件设计方法为什么要选择ICONIX呢?
第一是因为它所提供的方法让我着迷。这里不妨将它的概念抄录如下:
ICONIX过程的规模大概在重量级Rational Unified Process (RUP)和轻量纺的极限编程之间(XP)。同时
这种方法也是用例驱动,但不需要RUP使用记录延续到表中带来的大量开销。和XP一样,它相对较小,不像XP那
样摒弃了分析和设计过程。因此,有助于使用UML,同时对需求进行跟踪。该过程遵循Ivar Jacobson的用例驱
动思想,能够获得有形,具体,易于理解的用例,开发小组可以使用这个用例来驱动开发工作。
第二它解决了从用例到时序图的鸿沟(通过采用Robustness 中文译作"健壮性分析",也称鲁棒方法)。
也就是下图中所说的问题:
第三该方法是迭代,循序渐进同时足够的轻量级。因为它遵循20%原则,即用UML中20%的图表来完成设计中
80%的需求。从这个角度讲倒是满符合中国国情的,因为具我观察不少国内软件公司都不是肯花心思和时间在设
计架构上。
第四是就我个人而言的。其创始人DOUG ROSEBUG资深的设计经验,在我心中一直与MARTIN- FOLWER 是同量
级(甚至更厉害)的高人。(这里我有点像是这两位的马屁精了)
即然要使用这种方法,就有必要在这里对它里面的几个重要阶段做一下简要描述。首先请先看下图(p18)
其中的几个重要步骤包括(红字部分依旧对应上图中的相关位置):
1.(问题)域建模(Domain Model) 2.用例建模(User Case Model) 3.需求复核 4.健壮性分析(Robustness)
5.初步设计复核 6.时序图(Sequence Diagram,绘出设计级类图) 7.关键设计复核
本系列文章就是以上面这几步为蓝图,依次说明其各个阶段中所做的设计尝试和思考。
同时为了给大家一些帮助以及给自己做一些备注, 我会把书中所说的这几个阶段所经常出现的问题在每篇
文章的最后列出来。希望大家不要认为我是在揍字,而是因为这样做十分必要,一是给没看过这本书的人一个
提示,二是对看过这本书但可以已模糊内容的人一个温故知新的机会。也许正是这样的一种回味才会让自己的
设计思想更上一层楼。
开始今天的正文。问题域建模:
任务:作为 UML模型中的静态部分的基础,建立域模型时,首先确定直实世界中的抽象,即系统中将涉及
的主要的概念性对象。这种思想是因为真实世界发生变化的频率更低。
而为何要从域模型而不是用例开始是因为模型的动态部分(操作,方法)和静态(属性)部分结合起来,这对
于用例驱动设计而言是必须的。同时域模型起到了一个术语表的作用,用例编写者可以在编写用例的早期就使
用它。
同时这个阶段的起点是从系统的核心对象开始,由内向外工作,确定这些对象将如何参与要构造的系统。
还有就是这一阶段的主要任务就是要让开发团阶段对所开发的软件有一个全局上的了解。
而域类的来源就是资料,需求,问题陈述中的名词或名词短语。
好了,假定关于BLOG的用户需求(问题陈述)是这个样子的(因为个人时间和精力有限,这的活完成的比较糙,
还请大家见谅):
A: 游客需要通过注册(如通过)获取用户身份,而注册的用户可以在自己的管理后台对文章, 评论, 留言,
链接, 收藏, 相册, 下载文件(格式如RAR或ZIP), 签名, 个人信息,blog基本信息设置等相关信息。
(注:管理添加,删除,编辑等,另外就是这里忽略了诸如注册失败时系统所做出的反映等。)
用户在登陆后可以在前台浏览和回复本人其他人的文章和随笔。
后台管理员(相当于dudu的身份)可以管理系统中所有人的文章,包括置为精华贴),创建俱乐部(或群)
之类的组,对用户注册信息进行审核等。
B:而次要的如管理显示聚合数据,收藏, RSS。管理备份功能,日志。皮肤等就一带而过了。
注意:这里使用了“等等”之类模糊的甚至是不明确表述,就我个人看来这是要在项目设计中尽量
避免的。而有关需求的获取和描述可以参考一些相关书籍,但不要过于沉迷了其中,以免失去目标。
到这里,主要的核心功能就说完了。下面开始采用名词和名词短词的方式来找出相应的域类:)
上面所述的需求描述A中存在如下名词:
游客,用户,文章,评论,留言,链接,收藏(此处为名词用法),相册,文件,blog, 基本信息,后台
管理员,精华贴,俱乐部(或群), 用户注册信息。
当然这里找出的名词不可能最终都成为域类,这里先简单进行一下分析。
游客:因此没有特定的有价值的个人信息(充其量只有Ip)。但如果采用用户组的方式来管理类似 "游客
组"的权限的话,它可能还会是一个有意义的信息。因此这里先不急于把它算上域类,等到动态建模 (用例和
时序图)时再确定它也不晚。
用户:这会是一个核心的类,主要的操作和系统功能和用例应该都是以它为核心展开的。
文章, 评论, 留言, 链接, 收藏, 相册都该算成域类,最低限度也应在数据库中应该有相应的表来记录相关的信息。
另外文章,收藏,相册可能都要有相应的类型,所以这里需要有相应的类型进行支持。因此引入了文章类型,收
藏类型,相册类型这三个域类。
下载文件:因为存在文件格式的差异所以这里应该有两个域类,一个是文件格式,一个是文件(自身的属性,
如名称,地址,大小等)。
注册信息和个人信息:这两者可近似看成是同一种东西,因为如果注册成功后所使用的信息内容(如EMAIL,
用户名)都将变成用户类的属性(所以这里就先略去了)。
签名:应该做为用户类中的一个属性会更合适:)
后台管理员:这是一个域类,但它本身应该作为是用户类的一个子类会更合适,因为管理员除了具备所有
用户的属性和操作之外,还有管理用户和系统管理等其它操作。
精华贴: 这个名称从我个人角度看它应该是对文章的一个特例,完全可用一个字段来标识文章是否是 "文
章精华"。当然您也可以把它当成一个域类,但我想前提是精华本身应该也是从随笔下派生出来,并且其应该
有文章所不具备的属性或操作。另外要说的就是在这里不该为到底如果对待这类名词而过多的浪费大家的时间。
因为在后续的设计工作中,这个问题会很恰当的被解决掉。必定问题域模型不是一个完美的模型,它只是 "帮
助开发人员了解自己要做的到底是个什么东西而已" 。当这一阶段任务已完成,就应快速进行下一个阶段(用
例建模)。必定公司是不会让大家在这种小事上任意扯皮的!
俱乐部(或群):这是一个域类,但我个人认为这里应该将它要分解成为两个域类,一个是俱乐部(或群)
表,用于以集合的方式展现,还有一个就是俱乐部类本身(其相关属性如名称,地点,站点链接等)。同样,
上面的有些域类如用户,相册也该有相关的表来存储相关信息,如果必要,完全可以参考这种方式进行分解:)
注:大家可以看到,上面所做的分析是很粗糙的。但如果事先的需求很明确的话,这里可以挖掘的信息
就会更多。但话又说回来了,如果过多过细的需求是好事但也可能是坏事。因为如果控制不当,它们会去误导
您偏离系统设计的核心。所以在这里不妨打个比方,挖掘用户需求就像是在挖一个坑,如果挖的坑过深过细最
后可以连自己都爬不上来了。我不想出来这种被用户需求“活埋”的情况,所以从系统整体出发适度分析是这
个阶段要时刻权衡考虑的。
经过这一轮PK 筛查,“幸存”下来的域类如下:
用户(含个人信息和签名), 用户列表, 文章,文章类型,评论,留言,链接,相册,相册列表, 相册
类型,文件,文件类型,blog基本信息,后台管理员,俱乐部。(这里姑且去掉游客和精华贴)
这样这一轮的"选手" 就可以进入下一轮(问题域建模)了。
为了方便起见,这里直接将相关的域类图放出来:
同时做简要说明如下:
用户与用户列表的关系是聚合关系,因为用户列表是由多个用户所组成。同样相册列表与相册也是这一
种关系。同时用户,文章这两个类是关联的,因为离开用户,文章也就失去了意义。同样文章与文件(也可叫
下载附件)也存在类似的关系。另外文件与文件类型之间是聚合关系(可能有人更愿意将它们看成是组合关系),
不过ICONIX方法认为争论这个问题毫无意义,因为这是详细设计阶段该解决的问题, 所以ICONIX方法更偏向
于用简单的聚集。类似的关系还有相册(相册类型),文章(文章类型)以及用户与俱乐部(群)。
而后台管理员与用户是一种继承的关系。
(注:这里的图只是一种表现形式,同时里面的一个类的层次关系只是先临时这样安排,而最终的结果如何
还要等到设计级类图才见分晓)
细心的朋友可能注意到了这里面并未将关联关系的细节表示出来(也可以说是多重度的关系),即类之间
是一对一,还是一对多或其它等等。而这正是ICONIX方法所强调的,因此这种方法认为在域建模期就确定这种
关系将占用大量时间,是导致分析瘫痪的主要原因之一。
还有就是这里的类都没有方法,这是因为没有足够的信息来确定方法该分配给那一个类,ICONIX方法认为
在进行交互建模阶段再进行方法分配是合理的。
另外就是这里的域类也不包含属性,因为这时还过早,很难说当前的属性是否就该属于这个类。(注:本人
对这个观点有所保留)
好了,目前这个阶段的工作基本完成了,最后再将这种方法所提出的在这一阶段经常出现的一些错误列出
来,以便给自己和各位朋友提个醒:)
十个最常见的域建模错误:
10.立刻给关联指定多重度(multiplicity),确保每个关联都有明确的多重度。
9.对名词和动词做过度的分析,而背离初衷。
8.不对用例和时序图进行研究,就将操作分配给类。
7.在确保已满足用户需求之前,对代码进行优化以提高重用性。
6.对于每个"部分(part-of)"关联,就使用聚集还是组合(composition)而争论不休。
5.未对问题空间进行建模之前,就假定一种具体的实现策略。
4.将类命名为难以理解的名称,而不是直观的名称。
3.直接进行实现结构,如友元关系和参数化类。
2.在域类和关系型数据库表之间建立1对1的映射。
1.对早的执行“模式化”,将导致根据同用户问题毫无关系的模式创建解决方案。