iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 23
1
自我挑戰組

Let's Eat GO ! 實務開發雜談by Golang系列 第 23

Day23 .[心得與討論篇] struct 設計解析 - 以melody package (3)

重新思考物件之間的關係

我們先稍稍拉遠,談談關於物件關係的設計,假設今天有個資料結構的題目是這樣:

有一位老師,老師有許多學生。

以前的我會如下面這樣寫:

// Student 學生
type Student struct {
	name string
}
// Teacher 老師
type Teacher struct {
	students []Student
}

但是其實這樣的寫法會衍生很多問題,老師與學生的關係實在太過緊密,要更改students內的任何一個學生的資料,都要透過Teacher,非常沒道理。

老師的學生,學生的老師,彼此有某種關連,但不代表著老師可以操控和實際擁有學生的一切。

後來筆者發現最好的解法辦法,就是用『指標』的方式替代,甚至是唯一解。

關於『指標』的認識,不要再限於只有:

如果拿到某某變數的指標,這邊改了理面的值,就連同原本變數所在之處,也會看到數值也跟著更改囉。

如果今天要筆者講解『指標』的話,寧可不從這種教科書式的講法開始,因為實際應用上這樣的知識,很難派上用場,甚至看過有人把『指標』當做『全域變數』的替代品,把『指標』丟得整個專案都是,為了可以隨時任意改變裡面的變數。

關於『指標』,最重要的部分,筆者認為應該是理解『有了某某變數的指標,等同於有了某某變數的位置』,有了這樣的認知,在設計golang專案的架構才能揮灑自如。

這點也許是從php開發跨到golang之間,很困難的ㄧ個阻礙,這個概念是以前沒有的,至少筆者在寫php的時候沒有看過,也沒人教過。

回到上面範例,想要表示老師有某些學生的關係,型態改寫成指標,變成如下這樣:

 // Teacher 老師
type Teacher struct {
	students []*Student
}

老師有著一群學生的『位置』,要指名某位學生的時候,可以利用這個『位置』找到想要的學生。

但實際上,這樣會稍微有點不方便,上面的宣告是用slice,如果用slice紀錄許多的元素,那麼當要找特定某個元素的時候,難免每次都要用for迴圈去找,超級麻煩而且效能很不好。

沒有道理,老師要找某個學生,不能直接找到他,而要依序每個人向每個學生詢問是不是要找的對象,實在太奇怪了。

我們改用Map來紀錄這件事情:

 // Teacher 老師
type Teacher struct {
	students map[*Student]bool
}

把學生的『位置』擺在map當中的key,利用index的方式,想找誰就找誰,不需要再一個一個問了。

也許你還會想知道,那我們既然我們的key是放學生的pointer,那麼value要放什麼呢?放什麼其實沒意義,反正也不會使用,所以隨便放個bool型態。

聰明的你,先在可能已經知道前篇整出的三個業務主體,其中的hub想法是什麼了吧?

type hub struct {
	sessions   map[*Session]bool
	broadcast  chan *envelope
	register   chan *Session
	unregister chan *Session
	exit       chan *envelope
	open       bool
	rwmutex    *sync.RWMutex
}

hub 記著許多session的位置(這個package其實是hub記了全數的session),而且需要的時候可以第一時間找到目標的session。

hub 和session有強烈的連結關係,但因為只是掌握session的指標,兩個業務主體並沒有耦合。

還記得指標的zero value是什麼嗎?是nil,放到map儲存的話,不需要的時候只要將該key從map刪掉即可。

好比這些對象的電話號碼,記在你的連絡人清單,有天不需要的時候,從清單刪除號碼就好,不用管對象的生死。

反之今天不是用指標的方式表達兩者的關係,那麼不需要目標對象的時候,可是要確確實實的幹掉它呢。


上一篇
Day22 .[心得與討論篇] struct 設計解析 - 以melody package (2)
下一篇
Day24 .[心得與討論篇] struct 設計解析 - 以melody package (4)
系列文
Let's Eat GO ! 實務開發雜談by Golang30

尚未有邦友留言

立即登入留言