面向对象的分析与设计

 

一、传统开发方法中存在的问题

        在二十世纪六十年代以前,软件系统都是较小且相对简单的;所用的编程语言都是十分简单(Fortran,Cobol等 );时兴个人英雄注意,即崇尚程序员的个人技能 ;代码是面条式的,特别是代码中含有GOTO语句。当时系统设计时常用的方法有功能分解法和数据流法。

1、功能分解法(function  decomposition)

        以系统需要提供的功能为中心来组织系统。首先定义各种功能,然后把功能分解为子功能,同时定义功能之间的接口。对较大的子功能进一步分解,直到可给出明确的定义。根据功能/子功能的需要设计数据结构和算法。其优缺点如下:

优点:

  • 当时的计算机应用还不是很普及,只是特定的用户按自己的需要,对软件系统做出了功能性的要求,有据可寻。 
  • 在相当大的程度上,解决了以前存在的问题。特别是与模块化编程结合使用,效率更高。
  • 删除GOTO语句,使得软件能得到有效的维护。
  • 与模块化编程相结合,使得软件能得到有效的维护  
  • 适用于功能稳定的应用领域,如某些科学计算。
  • 直接地反映用户的需求,所以工作很容易开始。

缺点:

  • 开头容易,结束难。
  • 结构化分析和设计注重处理功能,对所处理的数据放于次要的位置。
  • 对于众多的领域而言,其功能是易变的,如企业管理和商业管理。对需求变化的适应能力很差。
  • 局部的错误和局部的修改很容易产生全局性的影响。
  • 不能直接地映射问题域,很难检验分析结果的正确性。

 

2、数据流法(结构化分析法)

        又称作结构化分析。基本策略是跟踪数据流,即研究问题域中数据如何流动以及在各个环节上进行何种处理,从而发现数据流和加工。问题域被映射为数据流图(DFD),并用处理说明和数据字典进行详细说明。其优缺点如下:

优点:

  • 有严格的法则,逐步求精,较强调研究问题域。

缺点:

  • 在概念上,不能直接地映射到问题域中的事物
  • 对需求变化的适应能力较弱。
  • 大系统数据流和加工的数量太多,引起分析文档的膨胀。
  • 系统复杂时,难以检验分析的正确性。
  • 分析与设计的概念和表示法不一致,其转换规则也不严格。

3、分析

       上述的功能分解法和数据流发已经开发了很多软件系统。对于功能稳定的应用领域,如某些科学计算,上述方法是适用的。

        对于众多的领域而言,其功能是易变的,如企业管理和商业管理领域就是如此。因为随着市场的变化,要对这些领域的管理模式不断地进行调整。对于较为复杂的系统,用上述方法进行软件开发,容易导致模块的低内聚和模块间的高耦合,从而使得系统缺乏灵活性和可维护性。

        特别是由于当时团队的开发与管理方法的不足,使得在20世纪70年代的软件危机情况更加严重。

        为了解决软件危机,人们对开发技术进行了一定的改进,对编程语言也进行了革新,如产生了用于软件开发的4GL、CASE工具、原型技术和代码生成器。这些努力取得了一定的成就,但没有从根本上解决问题。 

 

二、面向对象基本概念

        面向对象方法的解决问题的思路是从现实世界中的客观对象(如人和事物)入手,尽量运用人类的自然思维方式来构造软件系统,这与传统的结构化方法从功能入手和信息工程化方法从信息入手是不一样的。在面向对象方法中,把一切都看成是对象。

1、面向对象的定义

        从程序设计方法的角度看,面向对象是一种新的程序设计范型(paradigm),其基本思想是使用对象、类、继承、封装、聚合、关联、消息、多态性等基本概念来进行程序设计。是一种运用对象、类、继承、封装、聚合、关联、消息、多态性等概念来构造系统的软件开发方法。

2、面向对象的基本思想

  • 从现实世界中客观存在的事物出发来建立软件系统,强调直接以问题域(现实世界)中的事物为中心来思考问题、认识问题,并根据这些事物的本质特征,把它们抽象地表示为系统中的对象,作为系统的基本构成单位。这可以使系统直接映射问题域,保持问题域中事物及其相互关系的本来面貌(对象)
  • 用对象的属性表示事物的性质;用对象的操作表示事物的行为。(属性与操作)
  • 对象的属性与操作结合为一体,成为一个独立的、不可分的实体,对外屏蔽其内部细节。(对象的封装)
  • 对事物进行分类。把具有相同属性和相同操作的对象归为一类,类是这些对象的抽象描述,每个对象是它的类的一个实例。 (分类)
  • 复杂的对象可以用简单的对象作为其构成部分。(聚合)
  • 通过在不同程度上运用抽象的原则,可以得到较一般的类和较特殊的类。特殊类继承一般类的属性与操作,从而简化系统的构造过程及其文档。(继承)
  • 类具有封闭性,把内部的属性和操作隐藏起来,只有公共的操作对外是可见的。 (类的封闭性)
  • 对象之间通过消息进行通讯,以实现对象之间的动态联系。   (消息)
  • 通过关联表达类(一组对象)之间的静态关系。(关联)

3、面向对象中的基本原则

1.抽象

过程抽象:任何一个完成确定功能的操作序列,其使用者都可把它看作一个单一的实体,尽管实际上它可能是由一系列更低级的操作完成的。

数据抽象:根据施加于数据之上的操作来定义数据类型,并限定数据的值只能由这些操作来修改和观察。

 

客观事物->对象->类->一般类

不同开发阶段需要进行不同程度的抽象,便于实现模块的可替换性

2.封装

        把对象的属性和操作结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。只是向外部提供接口,降低了对象间的耦合度。

封装的意义:

  • 使对象能够集中而完整地描述并对应一个具体事物。
  • 体现了事物的相对独立性,使对象外部不能随意存取对象的内部数据,避免了外部错误对它的“交插感染”。
  • 对象的内部的修改对外部的影响很小,减少了修改引起的“波动效应”。
  • 公开静态的、不变的操作,而把动态的、易变的操作隐藏起来。

封装机制保证:数据不能被对象的使用者直接访问。只允许通过由对象提供的方法或代码访问数据。

3.委托

        借助消息传递,工作可从一个对象(客户)传递到另一个对象(代理),因为从客户的观点,代理具有客户所需要的操作。工作连续地传递,直到到达了既有数据又有方法(代码)能完成这项工作的对象。 

注意:委托是执行任务的权利,而不是责任。

4.分类

        把具有共同性质的事物划分为一类,得出一个抽象的概念。分类帮助我们组织我们所生活的复杂世界。我们可以对在一个特殊分类中的对象做一些假设。如果一个对象是分类(类)的一个实例,它将符合该分类的总体模式。所有的对象都是类的实例。实例能够在运行时被产生(初始化)或销毁(删除)。对象怎样提供操作,由该对象为其实例的类所决定。这样,同一个类的所有对象在响应特定的操作请求(功能调用)时使用相同的方法

5.泛化

无多态性的泛化:类可以由层次继承结构所组织。在该结构中,子类将从位于层次结构高层的父类中继承属性、操作和关系。抽象的父类是指仅用来定义子类的超类。这样,抽象类就没有直接的实例。

 

有多态的泛化:可以使用层次继承结构组织类,子类可以继承位于层次结构的高层的父类的属性、操作和关系。然而,子类可以定义它自己的操作来代替其任何超类的同名操作。

6.消息通信

        即要求对象之间只能通过消息进行通讯。消息传递机制与函数调用机制的区别 :

  • 在消息传递机制中,每一个消息被发送给指定的接收者(对象)。在命令式编程范型中,函数调用机制没有指定的接收者。
  • 消息的解释(用来完成操作请求的方法或操作/代码集)依赖接收者,并且因接收者的不同而异。
  • 在面向对象的范型中,通常在运行时才能知道给定消息的特定的接收者。

7.关系机制

        关系机制为我们提供了用同等(关联、依赖)和层次(一般化/特殊化和聚合)结构组织类/对象的方法。很多面向对象的专家把模型的这部分结构称作静态模型。我们使用James Martin和James Odell的术语,将其称为结构分析。然而,一个应用/系统有了结构分析并不充分,还需要进行行为分析。行为分析是我们用来考察一个对象(类)是怎样提供它的操作的过程。 从分析的视点,有两种类型的行为:

静态的:在静态行为中,实现操作的代码不被任何外部或内部的事件(动作)所影响。

动态的:在行为中发生这些变化的原因可能是由于对象存在很多不同的状态。随后,对象根据它的状态做出反映。使用命令式编程技术不能很好地处理这种类型的行为。使用另外的一种称为有限状态机的机制会更好地捕获这样的方法。 

8.复杂性控制

        引入包(package) 的概念,使模型具有大小不同的粒度层次,以利于控制复杂性。 如把分析和设计阶段的模型分别用包进行组织。

 

说明:书上=》抽象、分类、封装、消息通信、多态性、行为分析、复杂性控制

4、关键字说明

对象

        对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组操作构成。

 

对象标识

        对象标识就是对象的名字,有“外部标识”和“内部标识”之分。

 

        类是具有相同属性和操作的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和操作务两个主要部分。类的作用是用来创建对象,对象是类的一个实例。

 

抽象

        抽象(化)忽略事物的非本质特征,只注意那些与当前目标有关的本质特征,从而找出事物的共性。

 

分类

        把具有共同性质的事物划分为一类,得出一个抽象的概念,叫做分类。

 

继承

        特殊类拥有其一般类的全部属性与操作,称作特殊类对一般类的继承。继承意味着自动地拥有,或曰隐含地复制子类从父类中继承属性和操作,根据需要添加自己的属性和方法。继承简化了人们对事物的认识和描述,非常有益于软件复用,是OO技术提高软件开发效率的重要原因之一。一般类与特殊类之间的关系叫泛化关系(继承关系),简称泛化。例:

面向对象的分析与设计_第1张图片

 

多态

     多态是指同一个命名可具有不同的语义。OO方法中,常指在一般类中定义的属性或操作被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。 

 

 消息

       对象通过它对外提供的操作在系统中发挥作用。当系统中的其他对象或其他系统成分(在不要求完全对象化的语言中,允许有不属于任何对象的成分,例如C++程序中的main函数),请求这个对象执行某个操作时,该对象就响应这个请求,完成该操作。在OO方法中,把向对象发出的操作请求称为消息。目前在大部分面向对象的编程语言中,消息其实就是函数(或过程)调用。但是,函数调用只是实现消息的方式之一,上述理解只适合于顺序系统。 

 

聚合 

        一个(较复杂的)对象由其他若干(较简单的)对象作为其构成部分,称较复杂的对象为聚集,称较简单的对象为成分,称这种关系为聚合。如:

面向对象的分析与设计_第2张图片

UML表示举例:

面向对象的分析与设计_第3张图片

 

关联

         类之间的静态联系称作关联。在实例化后,由类产生对象,由关联产生连接对象的链。

链是关联的实例。 关联的表示符号也称作实例连接:

面向对象的分析与设计_第4张图片

 5、面向对象优点

与传统方法相比,面向对象方法的主要优点:

  • 把易变的数据结构和部分功能封装在对象内并加以隐藏,  

    一是保证了对象行为的可靠性;

    二是对它们的修改并不会影响其他的对象,有利于维护,对需求变化有较强的适应性。

  • 封装性和继承性有利于复用对象。

   把对象的属性和操作捆绑在一起,提高了对象(作为模块)的内聚性,减少了与其他对象的耦合,这为复用对象提供了可能性和方便性。在继承结构中,特殊类对一般类的继承,本身就是对一般类的属性和操作的复用。  

三、面向对象分析

1、基本介绍

        面向对象的分析(Object Oriented Analysis, OOA),就是运用面向对象方法进行系统分析。其基本任务即运用面向对象方法,对问题域和系统责任进行分析和理解,找出描述问题域及系统责任所需的对象,定义对象的属性、操作以及它们之间的关系。其目标是建立一个符合问题域、满足用户需求的OOA模型。

        OOA是分析,是软件生命周期的一个阶段,具有一般分析方法共同具有的内容、目标及策略;强调运用面向对象方法进行分析,用面向对象的概念和表示法表达分析结果。

 

问题域(problem domain):被开发系统的应用领域,即在现实世界中由这个系统进行处理的业务范围。

系统责任(system responsibilities):所开发的系统应该具备的职能。

2、OOA模型

面向对象的分析与设计_第5张图片

 四、面向对象设计

        从OOA到OOD不是转换,是调整和增补。使OOA作为OOD模型的问题域部分;增补其它四个部分,成为完整的OOD模型。

面向对象的分析与设计_第6张图片

 有不同的侧重点和不同的策略

OOA主要针对问题域,识别有关的对象以及它们之间的关系,产生一个映射问题域,满足用户需求,独立于实现的OOA模型。

OOD主要解决与实现有关的问题,基于OOA模型,针对具体的软、硬件条件(如机器、网络、OS、GUI、DBMS等)产生一个可实现的OOD模型。

1、人机交互

        人机交互、人机互动(Human–Computer Interaction或Human–Machine Interaction,简称HCI或HMI),是一门研究系统与用户之间的交互关系的是科学学科 。把人机交互部分作为系统中一个独立的组成部分,进行分析和设计,有利于隔离界面支持系统的变化对问题域部分的影响。人机交互使用的设备主要有键盘显示、鼠标、各种模式识别设备……

1.人机交互部分的需求分析

对使用系统的人进行分析

——以便设计出适合其特点的交互方式和界面表现形式;

对人和机器的交互过程进行分析

——核心问题是人如何命令系统,以及系统如何向人提交信息。

1.分析与系统交互的人——人员参与者

        人对界面的需求,不仅在于人机交互的内容,而且在于他们对界面表现形式、风格等方面的爱好。前者是客观需求,对谁都一样;后者是主观需求,因人而异。

(1)列举所有的人员参与者

(2)调查研究

(3)区分人员类型

(4)统计(或估算)各类人员的比例

(5)了解使用者的主观需求

 (6) 按照一定的准则进行折中与均衡 

2.从use case分析人机交互

use case的构成

参与者的行为和系统行为按时序交替出现,左右分明。形成交叉排列的段落。

每个段落至少含有一个输入语句或输出语句;

有若干纯属参与者自身或系统自身的行为陈述;

可能包含一些控制语句或括号。

 

抽取方法:

删除所有与输入、输出无关的语句和不再包含任何内容的控制语句与括号,

剩下的就是对一个参与者(人)使用一项系统功能时的人机交互描述。

面向对象的分析与设计_第7张图片

2.人机界面的设计

        人机界面的设计准则:

  • 易学、易用、操作方便 
  • 尽量保持一致性 
  • 及时提供有意义的反馈 
  • 使用户的注意力集中在当前的任务上而不是界面上 
  • 尽量减少用户的记忆 
  • 具有语境敏感的帮助功能 
  • 减少重复的输入和操作 
  • 对用户的操作具有容错性 ,如UNDO
  • 防止灾难性的错误 
  • 其它:如艺术性、趣味性、风格、视感等

1.命令的组织

不受欢迎的命令组织方式:

(1)一条命令含有大量的参数和任选项

(2)系统有大量命令,不加任何组织和引导

 

基本命令:使用一项独立的系统功能的命令。(提取后的用况)

命令步:在执行一条基本命令的交互过程中所包含的具体输入步骤。

高层命令:如果一条命令是在另一条命令的引导下被选用的,则后者称作前者的高层命令。

 

命令的组织措施——分解与组合

(1)分解:将一条含有许多参数和选项的命令分解为若干命令步

(2)组合:将基本命令组织成高层命令,从高层命令引向基本命令

 

基本命令及其命令步的结构

 面向对象的分析与设计_第8张图片

 

 高层命令及其结构

面向对象的分析与设计_第9张图片

 按功能组织:如文件下有:创建、打开、关闭、打印、删除等。

按子系统组织:如文本编辑子系统、编译自系统。

 

两层命令之间的输出信息结构

面向对象的分析与设计_第10张图片

 

 在建立命令树时,应遵循如下策略:

  • 把使用最频繁的命令放在前面,按照用户的工作步骤进行排列。
  • 在命令中发现整体-部分模式,以帮助对命令的组织与分块。
  • 每层命令的个数应遵循7+2原则,命令的层次深度尽量要控制在三层以内。

2、控制驱动部分的设计

        控制流是进程(process)或线程(thread)的别称。有多个任务(控制流)并发执行的系统,称作多任务系统或并发系统。为了描述问题域固有的并发行为,表达实现所需的设计决策,需要在OOD部分对控制驱动部分进行建模。控制流驱动部分,用于定义和表示并发系统中的每个控制流。用主动对象表示每个控制流(进程、线程),所有的主动类构成控制流驱动部分。

        在面向对象中,用一个主动对象表示一个独立的控制流,该对象驱动进程或线程,也即每个控制流都以一个表示独立的进程或线程的主动对象为根。 对控制驱动部分建模,通常,

  • 用包括主动类的类图捕捉控制流的静态结构
  • 用包括主动对象的顺序图或通信图捕捉控制流的动态行为

1.识别控制流

1)OOA定义的主动对象,这是由业务逻辑所决定的

2)系统的并发需求所要求的多控制流,若要求多项工作同时进行,则每一项工作就是一个控制流。例如,销售与统计。

3)系统分布方案所要求的多控制流,每一个分布站点至少有一个控制流

4)根据任务的紧急程度设置控制流,高优先控制流,低优先控制流,紧急控制流;

5)为实现方便设立的控制流,例如:负责处理机之间通讯的控制流

6)对异常事件的处理,由于异常事件的发生,不能在程序的某个可预知的控制点进行处理,应该设立一个专门的控制流进行处理异常事件。

2.审查与调整

  • 过度并发性意味着执行效率的损失;
  • 考虑控制流之间职责的均衡分布情况,它们之间协作的情况,以保证每个控制流是高内聚的,且与相关的控制流是松耦合的;

每个控制流应该有以上列举的理由之一,除非由明确的其他理由。

3.控制流间的通信

  • 操作调用

    一个控制流中的对象调用另一个控制流中的对象的操作,是通过发送了一条同步消息来实现的。具体的执行步骤为:

      (1)调用者调用操作 

      (2)调用者等待接收者接收这个调用

      (3)接收者的操作被唤醒

      (4)计算结果返回给调用者

      (5)调用者继续它的执行。

  • 邮箱

      一个控制流的对象异步地向另一个控制流中的对象发送一个信号。具体的执行步骤为:

     (1)请求者发送信号,然后就继续它自己的执行;

     (2)接收者只有在准备好时或在适当的时候,才到指定的邮箱去接收信号并进行处理,完成后可能向请求者发信号来回传处理结果,接着向下执行。

      这样的邮箱机制也可以是同步的,但收发信号的双方事先要做好约定。

  • 共享存储器

    两个或几个控制流中的对象利用一块公共的存储器,作为通信区域。

    通常传输具有较复杂和较大的数据结构的数据时,才使用共享存储器方式。

    使用此方式,要注意同步问题。

  • 远程过程调用

       用于在不同计算机中的并发进程:

      (1)调用进程标示它想要请求的一个对象的操作,然后把它放在远程过程调用库中;

      (2)远程过程调用机制在网络上寻找目标对象,找到后将请求打包发送给目标对象;

      (3)目标方接到后将请求转换成本地格式,执行所请求的操作;执行完毕后,将结果以上述同样的方式返回给发送方。 

3、数据管理部分的设计

        数据管理部分是负责在特定的数据管理系统中存储和检索对象的组成部分。其目的是,存储问题域的持久对象、封装这些对象的查找和存储机制,以及为了隔离数据管理方案的影响。为了隔离数据管理系统对其它部分的影响,使得选用不同的数据管理系统时,问题域部分基本相同。

1.面向对象数据库系统

        面向对象的数据库系统是OO设计和编程的之间扩展,是为了存储对象并与面向对象程序设计语言交互而专门设计的。它是按对象存储数据的数据库管理系统。面向对象数据库系统有两方面的特征:

(1)是面向对象的,应支持对象、类、操作、属性、继承、聚合、关联等面向对象的概念;

(2)另一方面它具有数据库系统所应具有的特定和功能。

4、构件及其部署设计

      当前的一种主流的做法是在面向对象的系统设计阶段的后期,考虑如何对系统的构件进行描述、构造和组织,以及构件如何在节点上进行分布。 

        1)  一个构件是系统的一个模块部分,而且是一个自包含的单元,它封装了其内部成分。

        2) 构件通过它的提供接口和请求接口展现行为。

        3) 构件是可替换的单元,在设计时和运行时依据接口的兼容性,若一个构件能提供与另一个构件所具有的功能,则前者可替换后者。

        4) 构件起类型的作用,这意味着构件是可实例化的。

构件的表示法 

面向对象的分析与设计_第11张图片

1.构件的接口

        接口(interface)接口由一组操作组成,它指定了一个契约,这个契约必须由实现和使用这个接口的构件的所遵循。除非用来表示常量,否则不需要属性。可以按各种约束(如前置和后置条件)的形式把一个接口与一个职责相关联,可以对通过这个接口的交互规定次序。接口分提供接口和请求接口。

        把构件实现的接口称为提供接口,这意味着构件的提供接口是给其它构件提供服务的。实现接口的构件支持由该接口所拥有的特征,包括接口拥有的约束。

        构件使用的接口被称为请求接口,即构件向其它构件请求服务时要遵循的接口。即构件向其它构件请求服务时要遵循的接口 。

      一个构件可以实现多个接口,一个构件可以请求多个接口,一个接口可以由多个不同的构件实现。

面向对象的分析与设计_第12张图片

 2.构件的端口

        接口对声明一个构件的总的行为来说是有用的,构件的实现仅需保证要实现在全部的提供接口中的操作。使用端口是为了能进一步控制这种实现。作为构件的一个部件,端口描述了在构件与它的环境之间以及在构件与它的内部部件之间的一个显式的交互点。也即,端口是一个封装构件的显式的对外窗口,所有进出构件的交互都要通过端口。这明确地指出,构件可以拥有内部结构和形式化其交互点的一组端口。构件的外部可见行为恰好是它端口的总和。

 

3.连接件

        如果一个端口提供一个特定的接口而另一个端口需要这个接口,且接口是兼容的,那么这两个端口便是可连接的。连接件就是通过端口或接口用于构件实例间通讯的部件。 

面向对象的分析与设计_第13张图片

 为了连接构件或把端口与构件内的部件相连,UML定义了两种连接件:委托连接件和装配连接件。 

1. 装配连接件

        是两个构件实例间的连接件,它定义一个构件实例提供服务,另一个构件实例使用这些服务。装配连接件用于把一个请求接口或端口与一个提供接口或端口的连接起来。在执行时,消息起源于一个请求端口,沿着连接件传递,被交付到一个提供端口 

2.委托连接件

        把外部对构件端口的请求分发到构件内部的部件实例进行处理,或者通过构件端口把构件内部部件实例向构件外部的请求分发出去。

 

委托有这样的含义:

        具体的消息流将发生在所连接的端口之间,可能要跨越多个层次,最终到达要对消息进行处理的最终部件实例。这样,使用委托连接件可对构件行为的层次分解建模。

你可能感兴趣的:(设计分析)