面向对象范式分析和设计流程
1.第0阶段:制定计划2.第1阶段:我们在做什么3.第2阶段:我们将如何建立对象3.1对象设计的五个阶段3.2对象开发准则 4.第3阶段:创建核心5.第4阶段:迭代用例6.第5阶段:进化7.计划的回报面向对象范式是一种新的,不同的编程思考方式,许多人一开始在学习如何处理一个OOP项目时都会感到非常困难。但是了解到任何事物都被认为是对象,并且学会用面向对象的风格去进一步思考之后,我们就可以开始利用OOP所提供的所有优点创造出“好的”设计。
如果我们正在考虑的是一个包含丰富细节而且需要许多步骤和文档的方法学,将很难判断什么时候停止。应当牢记我们正在努力寻找的是什么:
有哪些对象?(如何将项目分成多个组成部分?)它们的接口是什么?(需要向每个对象发送什么信息?)
只要我们知道了对象和接口,就可以编写程序了。由于各种原因我们可能需要比这些更多的描述和文档,但是我们需要的信息不能比这些更少。
整个过程可以分5个阶段完成,阶段0只是使用一些结构的初始约定。
1.第0阶段:制定计划
无论建造什么系统,不管如何复杂,都有其基本的目的,有其要处理的业务,有其所满足的基本需求。通过以此审视用户界面,硬件或系统的特殊细节,算法编码和效率问题,我们将最终找出它的核心,通常简单而又直接。就像来自好莱坞电影的所谓高层概念(high concept),我们能用一句或两句话表述。这种纯粹的表述是起点。
高层概念相当重要,应为它设定了项目的基调,这是一种任务陈述。我们不必一开始就让他正确(我们也许正处于在项目变得完全清晰之前的最后阶段),但是要不停地努力直到它越来越正确。例如:在一个空中交通指挥系统中,我们可以从关于正在建立的系统的一个高层概念入手:“塔楼程序跟踪飞机”。但是我们将这一系统收缩以适用于一个非常小的机场时,考虑将发生什么情况;可能只有一个控制人员甚至什么都没有。一个更有用的模型不应当像它描述问题那样多地关注正在创建的解决方案,例如“飞机到到,卸货,维修,重新装货和离开等”。
2.第1阶段:我们在做什么
这一阶段中我们有必要把注意力始终放在核心问题上:确定这个系统要做什么。为此,最具有价值的工具是一组所谓的“用例(use case)”。用例指明了系统中的关键特性,它们将展现我们使用的一些基本的类。它们实际上是对类似下述这些问题的描述性回答:
“谁将使用这个系统?”“执行者用这个系统做什么?”“执行者如何用这个系统工作?”“如果其他人也做这件事情,或者同一执行者有不同的目标,该怎么办?(揭示变化)”“当使用这个系统时,会发生什么问题?(揭示异常)”
例如,如果设计一个自动取款机,此系统的一个特定功能方面的用例能够描述这台自动取款机在任何可能情况下的行为。这些“情况”每一个称为情节(scenario),而用例可以认为是情节的集合。我们可以把情节认为是以“如果…系统将怎样?”开头的问题。例如,“如果一个用户在24小时内刚刚存了一张支票,且在此支票之外该账户没有足够的钱能满足提款要求,这时自动取款机怎么办?”。
下面的用例图特意进行了简化,以防止我们过早地陷入到系统的实现细节问题中去。
每个小人代表一个“执行者(actor)”,它通常是一个人或其他类型的自由代理(甚至可以是其他计算机系统,如“ATM”中的情况)。方框代表系统的边界。椭圆代表用例,是对此系统能完成的有价值工作的描述。在执行者和用例之间的直线代表交互。
只要符合用户的使用感受,系统实际上如何实现并不重要。用例不必十分复杂,即便底层系统非常复杂。这只是为了表示用户眼中的系统形象。
3.第2阶段:我们将如何建立对象
在这一阶段,我们必须做出设计,描述这些类和他们如何交互。UML提供了一种图形符号来描述系统的动态模型。在一个系统或子系统的状态转换占主导地位,以至于它们需要自己的图表情况下,还是有帮助的(例如在控制系统中)。我们可能还需要描述数据结构,因为系统或子系统中数据结构是重要因素(例如数据库)。
3.1对象设计的五个阶段
对象的设计生命周期不仅仅限于写程序的时间。实际上,它出现在一系列阶段上。接受这种观点很有好处,因为我们不再期望设计立刻尽善尽美,而是认识到,对对象做什么和它应当想什么的理解,会随着时间的推移而呈现。
对象发现这个阶段出现在程序的最初分析期间。对象可以通过寻找外部因素及边界,系统中重复的元素和最小概念单元而发现。
对象装配当我们正在建立对象时会发现需要一些新成员,这些新成员在对象发现时期未出现过。对象的这种内部需要可能要用新类去支持它。
系统构造随着不断学习,我们会改进我们的对象。与系统中其他对象通信和相互连接的需要,可以改变已有的类或要求新类。例如,我们可以发现需要辅助类,这些类如像一个链表,它们包含很少的状态信息或没有状态信息,只有帮助其他类的功能。
系统扩充当我们向系统增添新的性能时,可能发现我们先前的设计不容易支持系统扩充。这时,我们可以重新构造部分系统,并很可能要增加新类或类层次。
对象重用这是对类真正的强度测试。如果某些人试图在全新的情况下重用它,它们也许会发现一些缺点。当我们修改一个类以适应更新的程序时,类的一般原则将变得更清楚,直到我们有了一个真正可重用的对象。然而,不要期望从一个系统设计而来的大多数对象是可重用的,大量对象是对于特定系统的。可重用类一般共性较少,为了重用,它们必须解决更一般的问题。
3.2对象开发准则
下述步骤提出了考虑开发类时要用到的一些准则:
让特定问题生成一个类,然后在解决其他问题期间让这个类生长和成熟。记住,发现所需要的类(和它们的接口),是设计系统的主要内容。如果已经有了那些类,这个项目就不困难了。不要强迫自己在一开始就知道每一件事情,应当不断地学习。开始编程,让一些部分能够运行,这样就可以证明或否定已生成的设计。不要害怕过程型大杂烩式的代码——类的隔离性可以控制它们。坏的类不会破坏好的类。尽量保持简单。具有明显用途的不太清楚的对象比很复杂的接口好。当需要下定决心时,用Occam的Razor方法:选择简单的类,因为简单的类总是好一些。从小的简单的类开始,当我们对它有了较好的理解时再扩展这个类接口,但是很难从一个类中删去元素。
4.第3阶段:创建核心
这是从粗线条设计向编译和执行可执行代码体的最初转换阶段,特别是,它将证明或否定我们的体系结构。这不是一遍的过程,而是反复地建立系统的一系列步骤的开始,我们将在第4阶段中看到这一点。
建立这个系统的一部分工作是实际检查,就是对照需求分析和系统规范说明与测试结果(无论需求分析和规范说明以何种形式存在)。确保我们的测试结果与需求和用例相符。当系统核心稳定后,我们就可以向下进行和增加更多的功能。
5.第4阶段:迭代用例
一旦代码框架运行起来,我们增加的每一组特征本身就是一个小项目。在一次迭代期间,我们增加一组特征,一次迭代是一个相当短的开发周期。
在迭代期间的最后,我们得到一个集成的,测试过的,比前一周期有更多功能的系统。特别有趣的是迭代的基础:一个用例。每个用例是一组相关功能,在一次迭代中加入系统。这不仅为我们更好地提供了”用例应当处于什么范围内“的概念,而且还对用例概念进行了巩固,在分析和设计之后这个概念并未丢弃,它是整个软件建造过程中开发的基本单元。
6.第5阶段:进化
这是开发周期中,传统上称为”维护“的一个阶段是一个含义广泛的术语,包含了从”让软件真正按最初提出的方式运行“到”添加用户忘记说明的性能“,到更传统的”排除暴露的错误“和”在出现新的需求时添加性能“。所以,对术语”维护“有许多误解,它已经有点虚假的成分,部分因为它假设我们已经实际上建立了原始的程序,且所有的需要就是改变其中的一部分,加机油,防止生锈。也许,有更好的术语来描述所进行的工作。
此处将使用术语”进化“(evolution)也就是说,”我们不可能第一次就使软件正确,所以应该为学习,返工和修改留有余地“。当我们对问题有了深入的学习和领会之后,可能需要做大量的修改。
”使软件正确“的意思不止是使程序按照要求和用例工作,还意味着我们理解代码的内部结构,并且认识到它能很好地协同工作,没有笨拙的语法和过大的对象,也灭有难看的暴露的代码。另外,必须认识到,程序结构将经历各种修改而保全下来,这些修改贯穿整个生命期,也要认识到,这些修改是很容易进行和很简洁的。这可不是小成就。我们不仅必须懂得我们正在建造的程序,而且必须懂得这个程序将进化。
7.计划的回报
遵循计划(简单和短小的更加适宜),在编码之前就提出设计结构,我们会发现,事情总的说来比一上来就编码的方法容易得多,并且会认识到大多数情况是令人满意的。就我的经验,提出一个漂亮的方案,实际上是在一种完全不同水平上的满足,感觉上更接近于艺术,而不是技术。精致总是有回报的,这不是一种虚浮的追求。它不仅给出了一个容易建造和调试的程序,而且容易理解和维护,这就是其经济价值的体现。