原創 Go Official Blog Go Official Blog
2024年10月18日 19:10 中國香港 聽全文
在 Go 中,建立設計模式有助於管理物件的建立,並控制物件的例項化方式。這些模式在物件建立過程複雜或需要特殊處理時特別有用。以下是 Go 中常用的主要建立模式:
單例模式
單例模式確保一個類只有一個例項,並提供一個全域性訪問點。
如何實現
定義一個結構,並將其作為單個例項。
為該結構建立一個全域性變數,但不要立即將其初始化。
使用 sync.Once 確保例項只建立一次,即使在多執行緒情況下也是如此。
提供一個全域性函式來返回例項。
以下是實現單例模式的基本示例:
package main
import (
"fmt"
"sync"
)
type (
singleton struct {
data string
}
)
var instance *singleton
var once sync.Once
// Function to return the single instance
func GetInstance() *singleton {
// Use sync.Once to ensure the instance is created only once
once.Do(func() {
instance = &singleton{data: "This is a singleton"}
})
return instance
}
func main() {
s1 := GetInstance()
s2 := GetInstance()
// Both should point to the same instance
fmt.Println(s1 == s2) // true
fmt.Println(s1.data) // "This is a singleton"
}
sync.Once 可確保例項只建立一次,即使在併發呼叫 GetInstance 的情況下也是如此。
工廠方法模式
工廠方法模式定義了建立物件的介面,但允許子類改變將建立的物件型別。在 Go 中,這可以透過建立工廠函式來實現。這種設計模式提供一種將例項化邏輯委託給子類的方法,從而可以靈活地建立物件。
實現步驟:
建立一個為不同物件定義通用行為的介面。
建立多個實現此介面的結構體。
建立一個函式(工廠方法),接收一些輸入(如型別)並返回相應結構的例項。
以下是實現工廠方法模式的基本示例:
package main
import (
"fmt"
)
type Animal interface {
Speak() string
}
Dog struct{}
Cat struct{}
)
func (d Dog) Speak() string {
return "Woof!"
}
func (c Cat) Speak() string {
return "Meow!"
}
func AnimalFactory(animalType string) Animal {
if animalType == "dog" {
return &Dog{}
} else if animalType == "cat" {
return &Cat{}
}
return nil
}
func main() {
dog := AnimalFactory("dog")
fmt.Println(dog.Speak()) // Woof!
cat := AnimalFactory("cat")
fmt.Println(cat.Speak()) // Meow!
}
工廠方法允許建立不同型別的物件,但使用者端隱藏了建立邏輯。當物件建立過程比較複雜,需要進行抽象時,這種模式尤其有用。
抽象工廠模式
抽象工廠(Abstract Factory)提供了一個介面,用於建立相關或依賴物件的族,而無需指定它們的具體類。在 Go 中,可以透過定義不同的工廠介面來實現它。
當系統需要獨立於其物件的建立、組成和表示方式時,它就非常有用。它允許建立相關物件族。
以下是實現抽象工廠模式的基本示例:
package main
import (
"fmt"
)
// Define an abstract factory
type (
GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}
)
// Define interfaces for products
type (
Button interface {
Press() string
}
Checkbox interface {
Check() string
}
// Implement concrete products for Windows
WindowsButton struct{}
WindowsCheckbox struct{}
// Implement concrete products for Mac
MacButton struct{}
MacCheckbox struct{}
// Implement factories for each platform
WindowsFactory struct{}
MacFactory struct{}
)
func (w *WindowsButton) Press() string { return "Windows Button Pressed" }
func (w *WindowsCheckbox) Check() string { return "Windows Checkbox Checked" }
func (m *MacButton) Press() string { return "Mac Button Pressed" }
func (m *MacCheckbox) Check() string { return "Mac Checkbox Checked" }
func (w *WindowsFactory) CreateButton() Button { return &WindowsButton{} }
func (w *WindowsFactory) CreateCheckbox() Checkbox { return &WindowsCheckbox{} }
func (m *MacFactory) CreateButton() Button { return &MacButton{} }
func (m *MacFactory) CreateCheckbox() Checkbox { return &MacCheckbox{} }
func main() {
// Get a Windows factory
var wf GUIFactory = &WindowsFactory{}
button := wf.CreateButton()
checkbox := wf.CreateCheckbox()
fmt.Println(button.Press()) // Output: Windows Button Pressed
fmt.Println(checkbox.Check()) // Output: Windows Checkbox Checked
var mf GUIFactory = &MacFactory{}
button = mf.CreateButton()
checkbox = mf.CreateCheckbox()
fmt.Println(button.Press()) // Output: Mac Button Pressed
fmt.Println(checkbox.Check()) // Output: Mac Checkbox Checked
}
Builder 模式
構建器模式將複雜物件的構建與其表示分離開來,允許同一構建過程建立不同的表示。它能解決問題:複雜的物件通常是一步一步構建的。構建器模式為建立此類物件提供了靈活的解決方案,分解了例項化過程。
以下是實現構建器模式的基本示例:
package main
import (
"fmt"
)
// Product to be built
type House struct {
windows string
doors string
roof string
}
// Concrete builder for a villa
type VillaBuilder struct {
house House
}
// Director controls the building process
type Director struct {
builder HouseBuilder
}
)
// Builder interface
type HouseBuilder interface {
SetWindows() HouseBuilder
SetDoors() HouseBuilder
SetRoof() HouseBuilder
Build() *House
}
func (v *VillaBuilder) SetWindows() HouseBuilder {
v.house.windows = "Villa Windows"
return v
}
func (v *VillaBuilder) SetDoors() HouseBuilder {
v.house.doors = "Villa Doors"
return v
}
func (v *VillaBuilder) SetRoof() HouseBuilder {
v.house.roof = "Villa Roof"
return v
}
func (v *VillaBuilder) Build() *House {
return &v.house
}
func (d *Director) Construct() *House {
return d.builder.SetWindows().SetDoors().SetRoof().Build()
}
func main() {
director := &Director{}
// Build a villa
v_builder := &VillaBuilder{}
director.builder = v_builder
villa := director.Construct()
fmt.Println(*villa) // Output: {Villa Windows Villa Doors Villa Roof}
}
在建立需要大量可選配置的複雜物件時,建立者模式非常有用。
原型模式
原型模式允許透過複製現有物件(原型)來建立新物件,而不是從頭開始建立。當建立一個新物件的成本很高,而現有物件又可以克隆重用時,原型模式就派上用場了。
以下是實現原型模式的基本示例
package main
import (
"fmt"
)
// Cloneable interface
type (
Cloneable interface {
Clone() Cloneable
}
)
// Concrete struct (prototype)
type (
Product struct {
name string
category string
}
)
// Clone method creates a copy of the Product
func (p *Product) Clone() Cloneable {
return &Product{name: p.name, category: p.category}
}
func (p *Product) SetName(name string) {
p.name = name
}
func (p *Product) GetDetails() string {
return fmt.Sprintf("Product Name: %s, Category: %s", p.name, p.category)
}
func main() {
// Original product
original := &Product{name: "Phone", category: "Electronics"}
fmt.Println(original.GetDetails()) // Output: Product Name: Phone, Category: Electronics
// Clone the product and change its name
cloned := original.Clone().(*Product)
cloned.SetName("Smartphone")
fmt.Println(cloned.GetDetails()) // Output: Product Name: Smartphone, Category: Electronics
}
當建立物件的成本很高,而你又想透過複製現有物件來建立多個類似物件時,原型模式就很有效。這種模式透過克隆現有例項來簡化物件的建立,而不是從頭開始建立新例項。
總結
每種模式都有其特定的用例,選擇恰當的設計模式會使程式碼更有條理、可重用且更易於維護!
Go Official Blog
你的肯定是對我最大的鼓勵
閱讀原文
閱讀 630