在 DAY 1 ~ DAY 12 已经介绍了我认知常见的 concurrency patterns,接下来就要介绍经典的 GoF design pattern,但在这之前我认为可以先介绍一些 design pattern 的基本概念供大家有相同的认知,以便更清楚的讲解,所以接下来几篇会说明这些概念。
本篇要介绍的是 UML Class diagrams!
透过图形来说明物件建立、耦合、互动的关系
GoF design pattern 主要在讲解物件与物件的关系,如果直接把 code 贴出来,「一行一行」的程序码很难让刚接触此系统的人有「整体」的想像,俗话说「一张图,胜过千言万语」,Class diagrams 就是希望就由图来让人更快速的对此系统有初步的理解,所以应用在讲解 GoF design pattern 也是合适的。
但 Class diagrams 的定义没有一个统一标准,有许多规则的演变,但并不是每种都很常使用,我选择以下几种我认为最重要的规则,并且用mermaid-js绘画(使用教学可以看我这篇让你心里的逻辑具现化的念能力工具),实用与让人看得懂最为重要,如果规则太复杂让人无法理解就适得其反了。
先说明几个小细节:
(相关的 code 在Github - go-design-patterns)
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()
}
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{})
}
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)
}
Aggregation 聚合
A 拥有多个部件,并且这些部件与 A 的生命周期是不相同的,他们彼此不强制联系
跟组合类似,但关键差异是:
举例来说: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()
}
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()
}
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
Vue的安装方式有很多种像我这次是使用CND的方式来使用Vue 首先呢我们可以先到Vue的网站 可以...
今天要来解APCS的题目,这次是105年10月29的实作题第二题,那我们就开始吧! 题目 解答 a=...
前两篇介绍完 Vuex 的核心概念,最後当中大型专案需要组织较为复杂的资料结构时,总不可能一个 in...
**参考资料与文章在文章最下方!! **这篇有点长,大家看需要的地方就行 比比看: 因为节点上距离的...
如果你正在为水电或3C故障而苦恼,也许照着影片操作,是可以完成修复,但网路影片并非每一样技术都可以直...