UML类图中连接线与箭头的含义(转)
UML类图是描述类之间的关系
概念
1. 类(Class):使⽤三层矩形框表⽰。
第⼀层显⽰类的名称,如果是抽象类,则就⽤斜体显⽰。
第⼆层是字段和属性。
第三层是类的⽅法。
注意前⾯的符号,‘+’表⽰public,‘-’表⽰private,‘#’表⽰protected。
2. 接⼝:使⽤两层矩形框表⽰,与类图的区别主要是顶端有<>显⽰。
第⼀⾏是接⼝名称。
第⼆⾏是接⼝⽅法。
3. 继承类(extends):⽤空⼼三⾓形+实线来表⽰。
4. 实现接⼝(implements):⽤空⼼三⾓形+虚线来表⽰
5. 关联(Association):⽤实线箭头来表⽰,例如:燕⼦与⽓候
6. 聚合(Aggregation):⽤空⼼的菱形+实线箭头来表⽰
聚合:表⽰⼀种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不是A对象的⼀部分,例如:公司和员⼯
组合(Composition):⽤实⼼的菱形+实线箭头来表⽰
组合:部分和整体的关系,并且⽣命周期是相同的。例如:⼈与⼿
7. 依赖(Dependency):⽤虚线箭头来表⽰,例如:动物与氧⽓
8. 基数:连线两端的数字表明这⼀端的类可以有⼏个实例,⽐如:⼀个鸟应该有两只翅膀。如果⼀个类可能有⽆数个实例,则就⽤‘n’来
表⽰。关联、聚合、组合是有基数的。
重复度:
单重复度,只存在⼀对⼀的关系。
多重复度,⽤列表、vector或其它的数据结构维护⼀对多,多对多的关系
这⾥再说⼀下重复度,其实看完了上⾯的描述之后,我们应该清楚了各个关系间的关系以及具体对应到代码是怎么样的,所谓的重复度,也只不过是上⾯的扩展,例如A和B有着“1对多”的重复度,那在A中就有⼀个列表,保存着B对象的N个引⽤,就是这样⽽已。
形式:依赖/关联, 组合/聚合,继承/实现
荒谬的意思Dependency /Association,Composition/ Aggregation,Generalization/Realization
关联-属性指针-associate
1. 双向关联-相互关联,
** 相互把对⽅作为⾃⼰的指针**
C1-C2:指双⽅都知道对⽅的存在,都可以调⽤对⽅的公共属性和⽅法。
在GOF的设计模式书上是这样描述的:虽然在分析阶段这种关系是适⽤的,但我们觉得它对于描述设计模式内的类关系来说显得太抽象了,因为在设计阶段关联关系必须被映射为对象引⽤或指针。对象引⽤本⾝就是有向的,更适合表达我们所讨论的那种关系。所以这种关系在设计的时候⽐较少⽤到,关联⼀般都是有向的。
使⽤ROSE ⽣成的代码是这样的:
class C1{
public C2 theC2;
}
class C2 {
public C1 theC1;
}
双向关联在代码的表现为双⽅都拥有对⽅的⼀个指针,当然也可以是引⽤或者是值。
2. 单向关联-关联到它就把它当做⾃⼰的属性指针
C3->C4:表⽰相识关系,指C3知道C4,C3可以调⽤C4的公共属性和⽅法。
没有⽣命期的依赖。⼀般是表⽰为⼀种引⽤
⽣成代码如下:
class C3{
public C4 theC4;
}
class C4{
}
单向关联的代码就表现为C3有C4的指针,⽽C4对C3⼀⽆所知。
3. ⾃⾝关联(反⾝关联)-关联到⾃⼰,就是把⾃⼰当做属性指针
⾃⼰引⽤⾃⼰,带着⼀个⾃⼰的引⽤
代码如下:
class C5{
public C5 theC5;
}
就是在⾃⼰的内部有着⼀个⾃⾝的引⽤。
2.依赖-依赖
就把它的指针或引⽤,作为⾃⼰的函数形参-dependency
(1)单向依赖
依赖:
指C5可能要⽤到C6的⼀些⽅法,也可以这样说,要完成C5⾥的所有功能,⼀定要有C6的⽅法协助才⾏。C5依赖于C6的定义,⼀般是在C5类的头⽂件中包含了C6的头⽂件。ROSE对依赖关系不产⽣属性。
注意,要避免双向依赖。⼀般来说,不应该存在双向依赖。
ROSE⽣成的代码如下:
class C6
{
public void Func(C7 *pC7Obj);
}
class C7
{
}
(2)双向依赖
双向依赖关系图没有看到标准的画法,知道时候补上。
那依赖和聚合\组合、关联等有什么不同呢?
关联是类之间的⼀种关系,例如⽼师教学⽣,⽼公和⽼婆,⽔壶装⽔等就是⼀种关系。这种关系是⾮常明显的,在问题领域中通过分析直接就能得出。
依赖是⼀种弱关联,只要⼀个类⽤到另⼀个类,但是和另⼀个类的关系不是太明显的时候(可以说是“uses”了那个类),就可以把这种关系看成是依赖,依赖也可说是⼀种偶然的关系,⽽不是必然的关系,就是“我在某个⽅法中偶然⽤到了它,但在现实中我和它并没多⼤关系”。例如我和锤⼦,我和锤⼦本来是没关系的,但在有⼀次要钉钉⼦的时候,我⽤到了它,这就是⼀种依赖,依赖锤⼦完成钉钉⼦这件事情。
组合是⼀种整体-部分的关系,在问题域中这种关系很明显,直接分析就可以得出的。例如轮胎是车的⼀部分,树叶是树的⼀部分,⼿脚是⾝体的⼀部分这种的关系,⾮常明显的整体-部分关系。
上述的⼏种关系(关联、聚合/组合、依赖)在代码中可能以指针、引⽤、值等的⽅式在另⼀个类中出现,不拘于形式,但在逻辑上他们就有以上的区别。
这⾥还要说明⼀下,所谓的这些关系只是在某个问题域才有效,离开了这个问题域,可能这些关系就不成⽴了,例如可能在某个问题域中,我是⼀个⽊匠,需要拿着锤⼦去⼲活,可能整个问题的描述就是我拿着锤⼦怎么钉桌⼦,钉椅⼦,钉柜⼦;既然整个问题就是描述这个,我和锤⼦就不仅是偶然的依赖关系了,我和锤⼦的关系变得⾮常的紧密,可能就上升为组合关系(让我突然想起武侠⼩说的剑
不离⾝,剑亡⼈亡...)。这个例⼦可能有点荒谬,但也是为了说明⼀个道理,就是关系和类⼀样,它们都是在⼀个问题领域中才成⽴的,离开了这个问题域,他们可能就不复存在了
3.组合/聚合-属性对象-composite/aggreate
(1)组合-⾃⼰是实⼼的,去组合它,把它当做⾃⼰的属性对象,只是被组合的类不会单独存在(⾃⼰构造函数中使⽤)
组合(也有⼈称为包容):⼀般是实⼼菱形加实线箭头表⽰,如上图所⽰,表⽰的是C8被C7包容,⽽且C8不能离开C7⽽独⽴存在。但这是视问题域⽽定的,例如在关⼼汽车的领域⾥,轮胎是⼀定要组合在汽车类中的,因为它离开了汽车就没有意义了。但是在卖轮胎的店铺业务⾥,就算轮胎离开了汽车,它也是有意义的,这就可以⽤聚合了。
在《敏捷开发》中还说到,A组合B,则A需要知道B的⽣存周期,即可能A负责⽣成或者释放B,或者A通过某种途径知道B的⽣成和释放。他们的代码如下:
class C8
{
public C9 theC9;
}
class C9
{
}
可以看到,代码和聚合是⼀样的。具体如何区别,可能就只能⽤语义来区分了。
(2)聚合-⾃⼰空⼼的,去聚合它,把它当做⾃⼰的属性对象,被聚合的类可以单独存在(⾃⼰构造函数中不使⽤)
当类之间有整体-部分关系的时候,我们就可以使⽤组合或者聚合。
聚合:表⽰C9聚合C10,但是C10可以离开C9⽽独⽴存在(独⽴存在的意思是在某个应⽤的问题域中这个类的存在有意义。这句话怎么解,请看下⾯组合⾥的解释)。
代码如下:
class C10
{
public C11 theC11;
}
class C11
{
}
总结聚合和组合:
问题域的语义上:组合中被组合类单独存在没有意义; 聚合中被聚合类在可以有单独存在的意义。
⽣命期上:组合中必须要负责被组合类的⽣命期; 聚合中可不负责被聚合类的声明期,可以由外部程序来创建和消亡(可⽤赋值)。
4.泛化和实现 derived/implement
(1)继承(Derived)-⼦对象指向⽗对象
泛化关系:如果两个类存在泛化的关系时就使⽤,例如⽗和⼦,动物和⽼虎,植物和花等。
ROSE⽣成的代码很简单,如下:
class C12 extends C13
{
}
(2)接⼝实现(implement)
实现关系指定两个实体之间的⼀个合约。换⾔之,⼀个实体定义⼀个合约,⽽另⼀个实体保证履⾏该合约。
转⾃blog.csdn/blues1021/article/details/45739941