RUP(Rational Unified Process)和XP(极限编程)也不是非此即彼的关系,比如在造F-35的过程中,对整体飞机来说,用RUP是适合的,具体到零部件倒是大可XP一把,先在风洞里试验试验,不符合条件就更换了再试,最终只要得到最适合的零部件就OK了。
面向对象与面向过程不同的地方是,面向过程希望你通盘考虑,这时问题变得复杂化;而面向对象希望你把事物通过抽象角度分解成小块,问题就变得简单化。
越具体的事物越容易理解这个说法是一种误解,因为人们所认识的事物概念都是抽象的,具象只是一个相对的概念。实际上,由于人脑对信息的处理能力是有限度的,如果信息量超过了人脑的处理能力,人就会失去对这个事物的理解能力。因此,越是具体的表达信息量越大,越接近人脑的处理极限,人们的理解能力越是下降(这也是面向过程方法为什么困难的原因之一)。对面向对象方法来说,这时就需要提高抽象层次,用一个新的概念来概括一部分相关的信息,一旦人们像接受了光年概念一样消化了这个新的概念,理解起来就变得容易了。同时,这个新的概念就屏蔽了(或者说封装了)更多具体的信息。抽象层次越高,被屏蔽的信息也就越多,信息量越少,也就越容易理解和处理。这就是面向对象比面向过程具有优势的原因。
要深入了解对象,我们经常需要分析很多个该对象的实例所参与的场景,以获得对象的多个侧面,再通过归纳整理这些对象的多个实例抽象出对象的一般特性。这就是对象的分析方法,同时也是使用UML来为对象建模时所采用的方法。
对象是有着抽象层次的。层次越高,其描述越粗略但适应能力越广;层次越低则描述越精确但适应能力越下降。在分析过程中,应当根据问题领域的复杂程度设定多个抽象层次,在每个层次上使用适合的抽象程度的对象描述。这将有助于显著地减少分析的难度和工作量。
业务工人虽然不需要建立业务模型,但是他们是业务模型中非常重要的部分,经常出现的地方是领域模型(详见5.5节领域模型)和用例场景。缺少了他们业务模型就不完整,甚至不能运行。只有主角没有配角的戏没法演,而遇到一个像陈佩斯那样不配合的配角,戏一定也是演不好的。那么如何区分是参与者还是业务工人呢?最直接的办法当然是判断是在边界之外还是边界之内。如果边界尚不清楚,可以通过下面的三个问题帮助澄清:■ 他是主动向系统发出动作的吗?■ 他有完整的业务目标吗?■ 系统是为他服务的吗?这三个问题的答案如果是否定的,那一定是业务工人。
用例是相对独立的。这意味着它不需要与其他用例交互而独自完成参与者的目的。也就是说用例从“功能”上说是完备的。用例本质体现了系统参与者的愿望,不能完整达到参与者愿望的不能称为用例。例如取钱是一个有效的用例,填写取款单却不是,如图3.9所示。因为完整的目的是取到钱,没有人会为了填写取款单而专门跑一趟银行的。一个用例就是一个需求单元、分析单元、设计单元、开发单元、测试单元,甚至部署单元。一旦决定了用例,软件开发工作的其他活动都以这个用例为基础,围绕着它进行。
边界本质上是面向对象方法的一个很重要的概念,与封装的概念师出同源。面向对象里,任何一个对象都有一个边界,外界只能通过这个边界来认识对象,与对象打交道,而对象内部则是一个禁区。我们把边界放大了看,这个世界上任何一种东西我们都不可能知道它本质上是什么,而只能通过它的行为、外观、性质来描述它是一个什么东西。行为也好,外观也罢,这就是这个东西的一个边界,我们就是通过边界来认识事物的。
在建模的时候,如果是一个很庞大的系统,信息量之多会超出人脑的处理能力,进而失去分析能力。这就需要很好地把握抽象层次,排除掉非本层次之内的信息,自顶向下地把整个系统描述清楚。边界的设定可以帮上大忙。
以笔者自己的经验来看,能否准确把握边界,能否灵活变换边界,能否控制边界的粒度是做好需求分析和系统设计的关键。夸张一点说,高手和俗手之间的差别或许就在“心中有边界”吧!在架构师的眼里,再复杂的世界也是被许多无形的边界隔离、包装、各行其责的。一个好的分析和设计如同一筐带壳的鸡蛋,清清爽爽;一个差的设计如同一堆打碎了壳的鸡蛋,粘粘糊糊。壳,是好坏的关键。
边界类(boundary)、控制类(control)和实体类(entity)
作者不由得叹服宇宙规律的奇妙,复杂得无以伦比的神经网络和优秀的程序设计竟然有着如此微妙的相似:神经系统中两个神经元互不相连,通过突触交换信息;而在优秀的设计中,两个类也不直接相连,而是通过接口交换信息
对分析类来说,由于抽象层次高于实现方式,因此继续有效,而设计类却必须更改。这就是为什么要用分析模型来验证需求的原因之一,它能够大量地减少工作量和维护量。