具有层次形式
对于基本组件的选择在很大程度上依赖于系统观察者的判断
组件内部之间的联系比组件之间的联系更强
通常由几个不同种类的子系统通过各种排列组合而成
能够从简单系统演化而来
通用策略(大问题化小)
面向对象策略(拆分为各个组成部分)
类型抽象
服务激活抽象(函数调用、、时间处理、信息传递、订阅)
进程控制抽象(单程序执行、多任务、顺序执行、多线程)
关系抽象(关联、聚合)
行为(静态行为、动态行为)
规则(控制规则、业务规则、异常处理规则、竞争规则、触发器)
面向对象=对象+类+继承通信
适应性、可靠性
标识、分类、继承、多态
瀑布模型(不推荐)
迭代模式
用例视图、逻辑视图、实现视图、进程视图、部署试图
类是对“对象”的抽象
命名(要唯一):英文首字母要大写、中文也可。
public(+)
private(-)
protected(#)
package(~)
关联可以是一对一、一对多、可能是多对多
具体描述:
1:1个
0…1:0个或1个
0…*:0个或多个
子类的对象可以被用在父类的对象可能出现的任何地方,反之则不然
支持多态、可结构化描述、支持代码复用
任何基类出现的地方都可以被其子类替换
如果父类所有行为都可以替换,那继承关系成立,反之则不能。
java不允许多重继承,但可以通过接口实现类似功能
继承最重要的类、委派其他的类
只保留最重要的继承关系,把其余的继承关系变为组合关系
属性的枚举即其多重性。
用斜体字标识抽象类与抽象方法
包含多个状态图,每个类对应一个状态图
所有对象都有状态
状态时对象执行了一系列活动的结果
某事件发生后,对象的状态将发生变化
迁移的源和目标可以是相同的,也可以是不同的。
可以通过事件触发,或是内部活动自动触发
源状态
事件触发器
警戒条件(迁移条件的布尔表达式,用**[]括起来)
效应(迁移激活时执行的行为**)
目标状态
事件特征标记[警戒条件]/动作
e g : t a r g e t A t ( p ) [ i s T h r e a t ] / t . a d d T a r g e t ( p ) eg:targetAt(p)[isThreat]/t.addTarget(p) eg:targetAt(p)[isThreat]/t.addTarget(p)
eg:操作者按下开关按钮
eg:缓冲区溢出
事件名(事件参数表,用逗号隔开)
是对象之间的消息
由一个对象异步发送,并由另一个对象接收的已命名对象
用例版型:如“业务用例”,“业务用例实现”
类版型:如“信号类”,“接口”
考虑一组给定的主动对象可能响应的所有不同种类的信号。
寻找信号的公共种类,并使用继承将它们放在层次结构中。
在主动对象的状态机中寻找多态性,在发现多态性的地方,必要时通过引入中间的抽象信号来调整层次结构。
不断检测表达式,只要为真,事件就会发生。
when(表达式)/动作
when/at/after(表达式)/动作
其中,when和at是绝对时间事件,after是相对时间事件
entry/动作
exit/动作
尽量避免使用UML对用户界面建模
用户界面建模应结合用户界面设计图或者用户界面的原型(控件、布局等)
同一个用户可以在不同情况下扮演不同的参与者角色。
只描述系统的行为,而没有描述参与者行为
只描述参与者的行为,而没有描述系统的行为
在用例描述中就设定对于用户界面的设计要求。
描述过于冗长。
确定边界关系
确定关注参与者(每个参与者应该有单一、一致的目的)
每个用例必须给用户提供价值
关联用例与参与者
用例是非形式化的
用例可以结构化
为用例添加增量行为
A(扩展用例)->B(基用例),表示A是B的扩展
1.显示对象名与类名->“objectName:ClassName”
2.显示类名->“ClassName”
3.显示对象名->“objectName”
把参与交互的对象或角色放在图的上方,沿水平轴方向排列。
发起交互的对象或角色放在左边,较下级对象或角色依次放在右边。
把对象发送和接收的消息沿垂直轴方向按时间顺序从上到下放置。
可选执行:opt
条件执行:alt
并行执行:par
循环(迭代)执行:loop
所有对象都是并发活动的。
发送消息时,对象仍然保持活动状态,并可响应其他消息而不用等待响应。
限制一次可执行的对象数量。
被调用时才激活。
没有自己的控制线程。
执行完毕后控制权返回给调用者,被动对象重新变为不活动的。
至少为每个用例编写一种场景。
把场景抽象为顺序图。
划分复杂的交互。
为每种错误条件绘制一张顺序图。
交互图强调对象与对象之间的控制流。
活动图强调步骤到步骤之间的控制流。
表示算法语句或任务的执行。
执行进入动作,然后转向另一个状态
根据每个活动的职责对所有活动进行划分,每个泳道代表一个责任区。
一个泳道可能由一个或者多个类来实现。
分支:根据不同警戒条件转向不用活动,每个可能的转移即分支。
分叉:一个控制流被两个或多个控制流代替。并发进行
汇合:两个或多个控制流被一个控制流代替。并发进行
一个对象值,从一个动作流向另一个动作。
表示活动与对象之间的关系。
不要误用活动图
让图保持平衡
注意分支和条件
注意并发活动
系统构思:构思一项应用并系统地描述临时性需求。
分析:通过构造模型在更深入地理解需求。
系统设计:设计系统架构。
类设计:设计系统的真实模型及相关操作的算法。
实现:将设计转换成编码及数据库结构。
测试:确保应用满足实际需求。
培训:帮助用户掌握应用程序。
部署:安装应用软件,替代或连接已有系统。
维护:保证应用程序的长期有效性。
针对某种需求形成的新的想法。
新概念可能偏离原有系统。
5W1H:who,what.where,when,why,how
需求:从用户观点描述系统行为,系统被当作黑盒。
设计:选择适当的工程解决方案。
实现:将构思变成最终代码
描述要做什么,而不是怎么做!
问题描述本身可能是不完整、甚至错误的
分析模型:类模型(静态结构)、交互模型(交互)、状态模型(生存期)
分析阶段:领域分析(分析问题的真实本质)、应用分析(从应用的角度来分析系统)
目标:深刻理解需求,设计准确、间接、可理解、正确的真实世界模型
类模型优先级高于其他二者
1.静态结构容易定义
2.较少依赖应用程序的细节
3.解决方案演化时更稳定
应该被剔除的类:
1.冗余类(留下描述最清楚的)
2.无关类
3.定义模糊的类(界限模糊或定义宽泛)
4.对象属性:(当某些对象的独立存在不重要时,可描述为属性,反之则为类)
5.对象的操作(方法)(若某个对象的操作独立存在时没有意义,则不应定义为类)
6.角色(类名称应反映其本质,而不是它在关联中的角色)
7.软件实现中用到的结构
8.派生类
数据字典内容:
1.建模元素定义
2.类的作用域
3.受到的限制
4.关联、属性、操作、枚举
描述成属性还是描述成关联?
当类中的属性需要指向类时,可使用关联。
关联显示的了类之间的关系。
属性隐藏了类之间的依赖。
编码实现时可有多种方式,实现时两者差别不大。
关联的原则
如果删除关联中的一个类,则应删除该关联。
删除问题领域之外或与系统实现有关的关联。
关联应描述为问题的结构特性,而非临时事件
将三元关联分解为二元关联。
忽略派生关联(前面加“/”的关联名)
给关联适当的命名
适当增加关联终端名
适当使用限定关联
指定关联端的多重性
增加可能被遗漏的关联
不必太严格区分聚合、组合、普通关联。
寻找属性的原则
一个元素可以是属性也可以是独立类,视情况而定。
若属性值依赖于特定上下文,应使用限定符。
若名称依赖于上下文,则建模成限定符,反之则是属性。
不要把对象标识符建模成属性。
某些属性属于关联而不是类。
若某属性描述的是外部不可见的对象内部状态,则在分析阶段不应考虑。
在分析阶段忽略次要属性。
不要把无关属性整合在一起。
布尔属性扩展为枚举。
1.将现有类的公共部分泛化为类(自下而上)
2.将现有类特化为多个子类(自下而上)
原则:
1.慎用泛化
2.某些时候枚举比泛化更合适
3.慎用多重继承
4.可以考虑泛化关联类
5.适当的泛化层次
目的:跟踪类模型中的访问路径,确认是否产生符合实际的效果。
避免遗漏或错误地定义关联。
类中有无关属性和操作->拆分类
有相同名称或意图的重复关联->泛化出父类,组合重复的关联
一个描述类的语义的角色->设计成独立的类
遗漏了关联->增加新的关联
不必要的模型元素(缺少属性、操作、关联。有冗余信息)
关联终端名范围不适当
属性值之一需要访问对象
重新审视分析得到的类与关联
尽量把关联限制在单个包之中
可以在不同的包中重复一些内类
高内聚低耦合
1.确定具有状态的领域类
2.寻找状态
3.寻找事件
4.构造状态图
5.评价状态图
把系统看成黑盒(可与外界交互,内部细节隐藏 )
通常不把人看成系统
参与者可以人、外部设备、其他软件系统
参与者的行为不可预测,因此系统应足够健壮以应对参与者的各种行为
在描述的详尽程度上,各用例应保持一致
寻找用例事件开始,确定发起用例的参与者
寻找用例终止,确定用例应包含多少终止事件
外部事件:系统与用户或外部设备之间的交互导致的事件
输入、中断、决策等
顺序图描述主要流程,若有多个交互进程,用活动图合并
用户界面不是分析阶段的重点,且不应过分关注细节。
尽量确定用户可以执行的命令。
方便系统操作与接收来自外部资源的信息
将系统内部与外部隔离开
提供系统与外部资源通信的一个集结地
作用:接收外界或系统内部信号,响应信号并调用心痛对象上的响应操作,并给外界发送信号。
特点:以对象的形式来捕获数据和行为;多数应用的核心都是一项或多项控制器。
用多个状态来确定应用类
使用交互模型来寻找类的事件
用状态图为每个类组织许可的事件序列。
检查状态图,确保公共事件的匹配。
用类和交互模型检查状态图,确保一致。
对现有事物的复用
创建可复用的新事物进行复用(需要大量经验)
一组相关的类、关联、操作、事件和约束。
与其他子系统之间存在定义良好的小型接口。
通过它提供的服务(相关功能)来识别。
水平拆分:分层
闭合结构(减少耦合度):每一层只在其直接上下层之上构建。
开放架构(高效,高耦合度):某一层可以调用任一下层的功能。
垂直拆分:分区
分区和分层结合
必须是并发活动的对象
具有互斥活动的对象???
若两个对象在不交互的情况下可以在同一时间接收事件,则并发。
估算硬件资源需求
权衡硬件和软件
给处理器分配任务
确定物理连通性
文件形式:廉价、简单、持久
数据库形式:RDBMS,OODBMS
物理部件
空间
逻辑名称
对共享数据的访问
过程驱动型顺序控制流
时间驱动型顺序控制流(首选)
并发控制
过程调用
任务间的准并发调用
任务间的并发调用
接收输入信息,执行顺序计算,给出计算答案。
1.将整段拆分成不同阶段
2.为输入输出及每一对连续阶段,准备类模型
3.细化每个阶段,直到可以实现所有操作
4.重新构造最终的管道流程,以便优化
输出不断更新,依赖于不断发生变化的输入
1.将整个过程分为不同阶段,每个阶段完成一部分转换
2.为每一个连续阶段定义输入、输出与中间模型
3.区分不同的操作,以便获得每一阶段的增量变化
4.增加其他中间对象以便优化。
由系统和外部代理(人或设备)只配的系统
主要考虑系统和外部代理之间的通信协议、交互语法、输出表示、内部控制流、性能和错误处理
1.将界面类和应用类分离
2.尽量使用预定义的类与外部代理交互
3.以状态模型作为程序结构
4.分离物理事件和逻辑事件
5.明确所有界面调用的应用功能
对真实世界的对象进行建模与跟踪。
1.从类模型中确定主动的真实世界对象
2.确定离散事件,离散事件对应于对象的离散交互
3.确定连续的依赖性
对执行动作有着非常严格的时间约束的交互式系统
存储和检索数据的系统
1.将类模型映射成数据库结构
2.确定并发单元(不能共享的资源)
3.确定事务单元(必须一起访问的资源集合)
4.设计事务的并发控制
将分析阶段得到的类代入设计阶段,在类设计阶段对其进行细化
设计的本质:弥补实现功能与可用资源之间的差距
可通过构建中间元素来弥补差距
设计出能实现用例分析中的功能和操作对象
设计对象应该实现的操作
1.选择成本最低的算法
2.选择合适的数据结构
3.按需定义内部类和操作
4.把操作分配给合适的类
准确定义高层功能,设计时将其分解为小的、易实现的操作
缺点:高层功能描述的偏差将导致分解后的操作偏离实际需要
对系统的支持机制进行分层,从而构造系统
1.重新调成类和操作以增加继承性
2.从分组类中提取公共行为
3.当继承在语义上不合理时,使用委派来共享行为
隐藏内部信息使其不被外部视图所见
维护实体一致性
一个模块在扩展性方面应该是开放的,在更改性方面应该是封闭的。
1.使用接口进行封装
2.采用抽象机制
3.使用多态技术
子类必须能够替换掉它们的父类型,否则继承关系就是不正确的
类与类之间的依赖应该表现为依赖尽可能小的接口。
会带来严重的维护和重用方面的问题,被迫实现并维护不必要的方法
1.委托
2.多继承