Golang 常用的五种创建型设计模式
Golang 常用的五种创建型设计模式
原创 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