GoLang設計模式20 - 組合模式

robin·張 發表於 2022-01-23
設計模式 Go

定義

組合模式是一種結構型設計模式。

當我們想把一組物件當做一個整體來處理時就可以考慮使用組合模式。

組合模式被視為是介面型設計模式是因為它將一組物件組裝為一個樹狀結構。這個樹狀結構中的每個獨立元件都可以用同樣的方式來處理——無論它們是複雜的還是原始的。

以計算機作業系統中的檔案系統為例。在檔案系統中有檔案(File)和資料夾(Folder)兩類物件,在常見的各種使用場景中,它們的處理方式都差不多是一樣的。接下來我們會依據檔案系統對組合模式做更詳細的闡釋。

什麼時候使用

一、當從呼叫方的角度看來,組裝體和獨立元件需要以同樣的方式來處理時可以使用組合模式

在檔案系統中這個例子中,假設我們需要通過關鍵字來搜尋檔案。這個搜尋操作通常會對檔案和資料夾同時進行:

  • 對於一個檔案來說,會從檔案的內容中進行關鍵字檢索
  • 對於一個資料夾來說,會使用關鍵字遞迴遍歷檢索資料夾中的每個檔案

二、當組裝體和獨立元件可以組成一個樹狀結構時可以使用組合模式

檔案系統中的資料夾和檔案顯然是可以組成樹狀結構的。

UML Diagram

類圖如下:

GoLang設計模式20 - 組合模式

介紹下類圖中的各個組成部分:

  • 元件(Component):一個介面,定義了組裝體和葉子物件的共同操作
  • 組裝體(Composite):Component介面的實現,包含了一組子元件
  • 葉子(Leaf):樹結構中最基礎的物件,也實現了Component介面

檔案系統對應的UML類圖如下:

GoLang設計模式20 - 組合模式

程式碼

Component interface component.go

type component interface {
	search(string)
}

Composite folder.go

type folder struct {
	components []component
	name       string
}

func (f *folder) search(keyword string) {
	fmt.Printf("Serching recursively for keyword %s in folder %s\n", keyword, f.name)
	for _, composite := range f.components {
		composite.search(keyword)
	}
}

func (f *folder) add(c component) {
	f.components = append(f.components, c)
}

Leaf file.go

type file struct {
	name string
}

func (f *file) search(keyword string) {
	fmt.Printf("Searching for keyword %s in file %s\n", keyword, f.name)
}

func (f *file) getName() string {
	return f.name
}

client main.go

func main() {
	file1 := &file{name: "File1"}
	file2 := &file{name: "File2"}
	file3 := &file{name: "File3"}
	folder1 := &folder{
		name: "Folder1",
	}
	folder1.add(file1)
	folder2 := &folder{
		name: "Folder2",
	}
	folder2.add(file2)
	folder2.add(file3)
	folder2.add(folder1)
	folder2.search("rose")
}

程式碼已上傳至GitHub: zhyea / go-patterns / composite-pattern

END!!!