Golang 常用的五種創建型設計模式

在 Go 中,創建設計模式有助於管理對象的創建,並控制對象的實例化方式。這些模式在對象創建過程複雜或需要特殊處理時特別有用。以下是 Go 中常用的主要創建模式:

單例模式

單例模式確保一個類只有一個實例,並提供一個全局訪問點。

如何實現

  1. 定義一個結構,並將其作爲單個實例。

  2. 爲該結構創建一個全局變量,但不要立即將其初始化。

  3. 使用 sync.Once 確保實例只創建一次,即使在多線程情況下也是如此。

  4. 提供一個全局函數來返回實例。

以下是實現單例模式的基本示例:

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 中,這可以通過創建工廠函數來實現。這種設計模式提供一種將實例化邏輯委託給子類的方法,從而可以靈活地創建對象。

實現步驟:

  1. 創建一個爲不同對象定義通用行爲的接口。

  2. 創建多個實現此接口的結構體。

  3. 創建一個函數(工廠方法),接收一些輸入(如類型)並返回相應結構的實例。

以下是實現工廠方法模式的基本示例:

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