DAY 13:UML Class diagrams,在抽象世界的具现化宝石

在 DAY 1 ~ DAY 12 已经介绍了我认知常见的 concurrency patterns,接下来就要介绍经典的 GoF design pattern,但在这之前我认为可以先介绍一些 design pattern 的基本概念供大家有相同的认知,以便更清楚的讲解,所以接下来几篇会说明这些概念。

本篇要介绍的是 UML Class diagrams!

什麽是 UML Class diagrams?

透过图形来说明物件建立、耦合、互动的关系

GoF design pattern 主要在讲解物件与物件的关系,如果直接把 code 贴出来,「一行一行」的程序码很难让刚接触此系统的人有「整体」的想像,俗话说「一张图,胜过千言万语」,Class diagrams 就是希望就由图来让人更快速的对此系统有初步的理解,所以应用在讲解 GoF design pattern 也是合适的。

但 Class diagrams 的定义没有一个统一标准,有许多规则的演变,但并不是每种都很常使用,我选择以下几种我认为最重要的规则,并且用mermaid-js绘画(使用教学可以看我这篇让你心里的逻辑具现化的念能力工具),实用与让人看得懂最为重要,如果规则太复杂让人无法理解就适得其反了。

先说明几个小细节:

  • +号代表是公开属性或方法
  • -号代表是私有属性或方法
  • 线条上如果有数字,代表此物件在这整个关系上的数量

(相关的 code 在Github - go-design-patterns

  1. Generalization/Inheritance 继承

    A 会先定义好相关的属性与方法并且实作,而 B 继承 A 後,B 会拥有 A 相关的属性与方法,并且 B 也可有有自己的属性与方法

    举例来说:PS5 是继承自 PS4 而诞生的,PS5 能拥有玩 PS4 游戏的功能,但也可以玩 PS5 的游戏

    code 如下,需特别注意的是其实 golang 没有继承,只有组合(下方会介绍),但组合只组一项事物,也可以达到继承的效果:

    package main
    
    import "fmt"
    
    type PS4 struct {
    	PS4Game string
    }
    
    func (p PS4) PlayPS4Game() {
    	fmt.Printf("play %s", p.PS4Game)
    }
    
    type PS5 struct {
    	PS4
    	PS5Game string
    }
    
    func (p PS5) PlayPS5Game() {
    	fmt.Printf("play %s", p.PS5Game)
    }
    
    func main() {
    	ps5 := PS5{
    		PS4: PS4{PS4Game: "KOF14"},
    	}
    	ps5.PlayPS4Game()
    }
    
  2. Realization/Implementation 实作

    A 会先定义好相关的方法但不实作,而 B 必须以 A 的定义来实作相关方法

    举例来说:表演比赛说明来参赛的人只要会唱歌即可,所以不同的人种都可以参加

    code 如下:

    package main
    
    import "fmt"
    
    type Contestant interface {
    	Sing()
    }
    
    type Mike struct{}
    
    func (m Mike) Sing() { fmt.Println("mike singing") }
    
    type Kevin struct{}
    
    func (m Kevin) Sing() { fmt.Println("kevin singing") }
    
    type York struct{}
    
    func (m York) Sing() { fmt.Println("york singing") }
    
    func Show(contestant Contestant) {
    	contestant.Sing()
    }
    
    func main() {
    	Show(Mike{})
    	Show(Kevin{})
    	Show(York{})
    }
    
    
  3. Composition 组合

    A 拥有多个部件,并且这些部件与 A 的生命周期是相同的,他们彼此强制联系

    举例来说:PS5 拥有摇杆、CPU、显示晶片这些部件,这些部件是为了 PS5 而生

    code 如下:

    package main
    
    import "fmt"
    
    type PS5 struct {
    	CPU
    	Controller
    	GPU
    }
    
    type CPU struct{}
    type Controller struct{}
    type GPU struct{}
    
    func main() {
    	ps5 := PS5{
    		CPU{},
    		Controller{},
    		GPU{},
    	}
    	fmt.Println(ps5)
    }
    
  4. Aggregation 聚合

    A 拥有多个部件,并且这些部件与 A 的生命周期是不相同的,他们彼此不强制联系

    跟组合类似,但关键差异是:

    • 组合:是在定义 struct 的时候就要求把部件联系在一起
    • 聚合:是透过 function 去设置部件,所以不去设置也是可以的,因此彼此联系不强制

    举例来说:switch 可以买鼓组也可以买专用手把来玩太鼓达人,但不买也是可以玩的

    code 如下:

    package main
    
    import "fmt"
    
    type NintendoSwitch struct {
    	Controller string
    }
    
    func (n *NintendoSwitch) SetController(controller string) {
    	n.Controller = controller
    }
    
    func (n NintendoSwitch) PlayGame() {
    	if n.Controller != "" {
    		fmt.Printf("use %s to play game", n.Controller)
    	} else {
    		fmt.Println("use default controller to play game")
    	}
    }
    
    func main() {
    	nintendoSwitch := NintendoSwitch{}
    	nintendoSwitch.SetController("drum")
    	nintendoSwitch.PlayGame()
    }
    
  5. Association 关联

    A 的属性中拥有 B,并在 A 创建的时候带入 B

    跟聚合相似,但关键差异是:

    • 聚合是使用.SetXXX()这类的 function 将属性设置
    • 关联是在创建物件的时候就将属性设置

    但 golang 并不能再创建物件时就将属性设置,因为 golang 没有 construct,所以我们可透过一个CreateXXX()来模拟

    举例来说:我拥有 mac,我可以利用 mac 来去处理铁人赛文章

    code 如下:

    package main
    
    import "fmt"
    
    type Me struct {
    	Mac
    }
    
    type Mac struct{}
    
    func (m Mac) WriteArticle() {
    	fmt.Println("write article")
    }
    
    func CreateMe(mac Mac) *Me {
    	return &Me{mac}
    }
    
    func (m Me) WriteIronmanArticle() {
    	m.Mac.WriteArticle()
    }
    
    func main() {
    	me := CreateMe(Mac{})
    	me.WriteIronmanArticle()
    }
    
  6. Dependency 相依

    A 不拥有属性 B,但 A 的某方法有透过参数 B 来实现

    举例来说:我虽然不拥有公司白板,但我可以透过它来跟其他人沟通

    code 如下:

    package main
    
    import "fmt"
    
    type Me struct{}
    
    type Whiteboard struct{}
    
    func (w Whiteboard) DrawOnWhiteboard() {
    	fmt.Println("write")
    }
    
    func (m Me) Discuss(whiteboard Whiteboard) {
    	whiteboard.DrawOnWhiteboard()
    }
    
    func main() {
    	me := Me{}
    	me.Discuss(Whiteboard{})
    }
    

<<:  DAY26 - [React] 登入登出 router

>>:  Leetcode: 1791. Find Center of Star Graph

Day4 安装Vue

Vue的安装方式有很多种像我这次是使用CND的方式来使用Vue 首先呢我们可以先到Vue的网站 可以...

Python 练习

今天要来解APCS的题目,这次是105年10月29的实作题第二题,那我们就开始吧! 题目 解答 a=...

Day 19:有名模组,无限辅助-Vuex Modules、Map Helper

前两篇介绍完 Vuex 的核心概念,最後当中大型专案需要组织较为复杂的资料结构时,总不可能一个 in...

企业资料通讯 Week2 (讲到Circuit Switching v.s Packet Switching)

**参考资料与文章在文章最下方!! **这篇有点长,大家看需要的地方就行 比比看: 因为节点上距离的...

万事真能从影片完整复制学习吗?(厨艺篇)

如果你正在为水电或3C故障而苦恼,也许照着影片操作,是可以完成修复,但网路影片并非每一样技术都可以直...