@[toc]
1. 依赖和关联
1.1 依赖(Dependency)
概念
- 体现为局部变量、方法的形参,或者对静态方法的调用。
- 如:出行使用汽车,下雨打伞等
- 是一种弱关联关系,也是一种临时关系
类图示例
classDiagram
Person ..> Car
class Person{
+Travel(car Car)
}
class Car{
}
代码示例
package main
import "fmt"
//定义人的类
type Person struct {
Name string
}
//该类有旅行方法,需要车作为参数
func (p *Person) Travel(car Car) {
fmt.Printf("%q 坐着 %q 去旅行", p.Name, car.Name)
}
//定义一个汽车类,它是人的依赖
type Car struct {
Name string
}
func main() {
//实例化一个人
guanYu := &Person{
Name: "关羽",
}
//实例化一辆车
chiTu := &Car{
Name: "赤兔",
}
//执行人的旅行方法,车的实例作为参数
guanYu.Travel(*chiTu)
}
- 输出
"关羽"坐着"赤兔"取旅行
1.2 关联(Association)
概念
- 体现为类的属性,golang中可以表现为结构体的成员
- 如:我的朋友(聚合),人和身体部位(组合),汽车和轮子(组合)
- 是一种强关联关系,也是一种长期关系
类图示例
classDiagram
Person ..> Head
class Person{
+Head:Head
+Hand:String
}
class Head{
}
代码示例
参考下文 聚合、组合
2. 组合和聚合(特殊的关联关系)
2.1 聚合(Aggregation)
概念
- 是关联关系的一种,表示一种弱的“拥有”关系。
- 如人之于人群,苹果之于苹果堆
- 体现了群体和个体的关系
类图示例
主角
的朋友们
成员是由配角聚合而成的一群人,他们和主角不要求有相同的生命周期
classDiagram
Protagonist o-- SupportingRole
class Protagonist{
+Name:string
+Friends:List<SupportingRole>
}
class SupportingRole{
}
因为聚合也是一种特殊的关联关系,因此可以画成:
classDiagram
Protagonist o--> SupportingRole
class Protagonist{
+Name:string
+Friends:List<SupportingRole>
}
class SupportingRole{
}
代码示例
package main
import "fmt"
// 定义主角类
type Protagonist struct {
Name string
//它的一个成员是配角的切片
Friends []SupportingRole
}
//定义一个方法让配角加入主角的朋友(此处为了演示方便,和聚合关系无关)
func (p *Protagonist) AddFriend(supportingRoleList ...SupportingRole) {
p.Friends = append(p.Friends, supportingRoleList...)
}
//定义一个方法查看主角(此处为了演示方便,和聚合关系无关)
func (p *Protagonist) Get() {
fmt.Printf("%+v\n", p)
}
//定义配角类
type SupportingRole struct {
Name string
}
func main() {
//实例化一个主角——刘备
liuBei := &Protagonist{
Name: "刘备",
}
//实例化两个配角——关羽、张飞
guanYu := SupportingRole{
Name: "关羽",
}
zhangFei := SupportingRole{
Name: "张飞",
}
//将关羽、张飞加入刘备的朋友
liuBei.AddFriend(guanYu, zhangFei)
//查看刘备的信息
liuBei.Get()
}
- 输出
&{Name:刘备 Friends:[{Name:关羽} {Name:张飞}]}
2.2 组合(Composition)
概念
- 是关联关系的一种,表示一种强的“拥有”关系。
- 如:人之于头、脚;汽车之于驾驶室、发动机
- 体现了严格的部分和整体的关系
- 部分和整体的生命周期一样
类图示例
人
的组成部分包括头
,它们的实例有相同的生命周期
classDiagram
Person *-- Head
class Person{
+Head:Head
+Hand:String
}
class Head{
}
因为他也是一种特殊的关联关系,因此可以画成
classDiagram
Person *--> Head
class Person{
+Head:Head
+Hand:String
}
class Head{
}
代码示例
package main
import "fmt"
//定义一个类——人
type Person struct {
Name string
//他有一个成员是头
Head Head
}
//定义一个类——头
type Head struct {
weight float64
}
//写一个函数,用来实例化一个具体的人,这样保证了人和头的生命周期一致。(实际操作中可以写一个工厂)
func CreatePerson(name string, headWeight float64) (person *Person) {
person = &Person{
Name: name,
Head: Head{
weight: headWeight,
},
}
return person
}
func main() {
//实例化一个人——颜良(八斤半的头留给关羽摘吧)
yanLiang := CreatePerson("颜良", 8.5)
fmt.Printf("%+v", yanLiang)
}
- 输出
&{Name:颜良 Head:{weight:8.5}}
3. 实现和泛化(代码的重用)
3.1 实现(Realization)
概念
- 体现为类对接口的实现
- 比如接口
人
有工作
方法,其泛化类男人
、女人
都可以实现该接口的工作
方法
- 比如接口
类图示例
如概念中所述,
男人
和女人
都实现了接口人
的工作
方法
classDiagram
Person <|.. Man
Person <|.. Woman
class Person{
<<interface>>
+Work()
}
class Man{
+Work()
}
class Woman{
+Work()
}
因为是一种弱关系,因此我们可以看到是虚线链接
代码示例
package main
import (
"fmt"
)
//定义一个人的接口
type Person interface {
Work()
}
//定义男人类是接口人的实现
type Man struct {
Name string
}
func (m *Man) Work() {
fmt.Println("男人", m.Name, "开心的工作中")
}
//定义女人类是接口人的实现
type Woman struct {
Name string
}
func (w *Woman) Work() {
fmt.Println("女人", w.Name, "开心的工作中")
}
//定义一个函数实例化具体的人(实际代码中我们可以写成一个工厂)
func CreatePerson(name string, sex string) Person {
switch sex {
case "man":
return &Man{
Name: name,
}
case "woman":
return &Woman{
Name: name,
}
default:
return nil
}
}
func main() {
CreatePerson("周瑜", "man").Work()
CreatePerson("小乔", "woman").Work()
}
- 输出
男人 周瑜 开心的工作中
女人 小乔 开心的工作中
3.2 泛化(Generalization)
概念
- 是继承的逆向关系,子类是父类的泛化。
- 男人和女人也可以抽象出人类,此时男人和女人是人类的泛化。
类图示例
男人
是人
的泛化,不但继承了人
的还拥有胡子
classDiagram
Person <|-- Man
class Person{
+Name:String
+Head:String
}
class Man{
+Person:Person
+Beard:String
}
代码示例
package main
import "fmt"
//定义一个类——人
type Person struct {
Head string
Body string
}
//定义人的方法,用来设置人的属性
func (p *Person) SetPerson(head string, body string) {
p.Head = head
p.Body = body
}
//定义一个男人类,它是人的泛化(即它继承了人)
type Man struct {
Person
Bear string
}
//定义一个男人的方法,用来设置男人的属性
func (m *Man) SetMan(bear string) {
m.Bear = bear
}
func main() {
//实例化一个男人——关羽
guanYu := &Man{}
//设置关羽人的属性
guanYu.SetPerson("大头,红脸", "身高九尺")
//设置关羽男人的属性
guanYu.SetMan("长胡子")
//查看结果
fmt.Printf("%+v", guanYu)
}
- 结果输出
&{Person:{Head:大头,红脸 Body:身高九尺} Bear:长胡子}
image.png
网友评论