3.类图class diagram(必须)
1个类图描写了系统中对象的类型及他们间存在的各种静态关系static relationship。类图也展现了1个类的属性和操作properties and operations和对象相互连接的限制。uml使用属于feature特性来表示1个类的属性和操作。
类图中的盒子box表示类,它分成3部份:类名(粗体),属性attribute,操作operation。
【属性property】
property属性代表1个类的结构形态,但它以两种不同的标记出现:属性attribute和联系association
【属性attribute】
属性标记用类盒里的1个行文字描写1个属性。1个属性的完全格式是:
visibility name: type multiplicity = default {property-string}
例子:
- name: String [1] = "Untitled" {readOnly}
只有name是必须的。
・visibility 指明属性是public(+) or private(-)
・name 类如何称呼refer to该属性
・type 数据类型
・default value 若1个新创建的对象没有指定该属性时,使用这个值
・{property-string} 允许你指定这个attribute的附加的property,比如readOnly表示客户不能修改这个属性。如果不指定这个,表示属性可以修改。
【联系association】
attributes:
Order
+ dateRecv: Date [0..1]
+ isPrepaid: Boolean [1]
+ lineItems: OrderLine [*] {ordered}
associations:
Date <- Order -> Boolean
-> OrderLine
1个联系association是两个类之间的1条实线,从源类source class指向目标类target class。属性的名字和multiplicity在联系的目标终端。联系的目标终端是属性的类型type。特殊的,联系可以在线的两端显示多重性multiplicity。
1般,小东西的时候我使用属性attribute,比如1般的值类型。而更重要的类则用联系。
【甚么时候用类图】
建议:
・开始的时候用简单的:类,联系,属性,1般化generalization,限制constraint
・不要为所有东西画模型图,集中注意到重要的方面。
【多重性multiplicity】
表示这个属性会被多少对象充满,最普遍的是:
・1
・0..1
・*
zero or more
更1般的,1般定义1个下限和上限,比如2..4。下限是0和正数,上限是正数或*(无穷)。
多重性的属于:
・Optional: 下限0
・Mandatory: 下限1 或更多
・Single-valued: 上限1
・Multivalued: 超过1的上限:常常是*
如果我有1个多值的属性,我喜欢用复数命名。
如果顺序成心义,需要在联系的末端添加{ordered},如果允许相同,添加{nonunique},如果想显式的显示默许值,可用{unordered}和{unique}。
【双向的联系bidirectional association】
Person <-> Car
Car类有1个属性onwer: Person[1],Person类有1个属性cars: Car[*]。
【操作operation】
表示1个类要履行的动作actions that a class knows to carry out。1般你不能显示那些简单操作属性的操作,由于他们常常被推断。
操作的完全语法是:
visibility name (parameter-list) : return-type {property-string}
・visibility public+ private-
・name
・paramet-list 操作的参数列表
・return-type 返回值的类型(如果有的话)
・property-string
参数的格式是:
direction name: type = default value
direction表示参数是输入in,输出out或输入输出inout,默许是in。
例子:
+ balanceOn (date: Date) : Money
我常常觉得辨别改变和不改变系统状态的操作很有用。uml定义query为从1个类得到1个值但不改变系统状态的操作,就是没有副作用。你可以标记这类操作为{query}。我把改变状态的操作命名为modifiers,也叫命令commands。
严格讲,query和modifiers的区分是是不是改变可视察状态observable state。可视察状态是可以从外部感知到的状态。比如1个更新缓存的操作会改变内部状态,但不会影响从外部视察他。
我觉得高亮query很有用,由于你可以改变query的履行顺序而不改变系统的行动。
get和set方法应当算类的内部方法。
operation是指1个对象上的进程说明,而method是1个进程的身体。当你有多态的时候这两个不同。比如1个父类有3个子类,都重写了父类的getPrice操作,则有1个operation和4个method。
【1般化generalization】
使用继承的1个重要的准则是可替换性。比如我有1个Customer,则我可随便用Customer的任何子类。1个类是子类型subtype,如果他是父类的替换品,不论是否用了继承。subClassing子类是普通继承的同义词。
【笔记和注释】
可独立出现。
【依赖dependency】
两个元素间出现依赖,如果1个元素(供应者supplier)的定义的改变 会引发另外1个元素(客户)的改变。
类间的依赖多种:1个类发送消息给另外一个;1个类作为另外一个类的数据;1个类作为另外一个的某个操作的参数。
如果依赖超越控制,1个系统的每一个改变都会有很大影响致使更多的改变。这样就很难做改变。
uml允许你描写所有元素种类间的依赖。当你想显示1个元素改变以后可能怎样改变其他元素时可用依赖。
例子(当Employee改变的时候,Window可能需要改变):
Benefits Window - - > Employee - - > Employee Data Gateway
- - > Benefits Data Gateway
我发现严格的分展开示presentation和业务逻辑domain logic,让展现依赖业务而不反过来 这样很有价值。
另外就是Window没有直接依赖Data Gateway,若这些类改变了,Employee可能会改变。但如果改变只影响Employee的实现implementation,而不是接口interface,则改变停在那里。
基本的依赖是不可传递的transitive。某些类型的依赖,比如替换substitute是可传递的。但大多数例子中,在有向和无向依赖间有1个重要的区分。
1个子类依赖父类,但不反过来。
可选的依赖关键字:
call
src calls an operation in the targ
create
src creates instances of the targ
derive
src is derived from the targ
instantiate
src is an instance of the targ
permit
targ allows the src to
access the targ's private features
realize
src is an implementation of a specification or interface defined by the targ
refine
refinement indicates a relationship between different semantic levels
比如src多是1个设计类,而targ是相应的分析类analysis class
substitute
src is substitutable for the targ
trace
used to track such things as requirements to classes or how changes in one model
link to changes elsewhere
use
src requires the targ for its implementation
【限制规则constraint rule】
uml允许用任何东西来描写限制,唯1的规则是你要把他放到{}里。例子:
{disallow incest: husband and wife must not be siblings}