Golang 常用的五種創建型設計模式
在 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
}
當創建對象的成本很高,而你又想通過複製現有對象來創建多個類似對象時,原型模式就很有效。這種模式通過克隆現有實例來簡化對象的創建,而不是從頭開始創建新實例。
總結
每種模式都有其特定的用例,選擇恰當的設計模式會使代碼更有條理、可重用且更易於維護!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/OuQJR-PehZu3EncWdGGWGQ