返回

畅游设计模式,共赏Go语言的优雅之美

闲谈

设计模式,作为软件开发领域的宝贵财富,为代码的可重用性、可读性和可靠性提供了坚实的基础。它是一套反复使用、广为人知的代码设计经验总结,指导我们如何巧妙地构建软件系统。

在本文中,我们将携手踏上设计模式的探索之旅,从单例模式到工厂模式,从策略模式到观察者模式,全面解析23种经典设计模式。同时,我们将借助Go语言的代码实现,生动诠释这些模式的精髓,领略Go语言的优雅与灵动。

1. 单例模式

单例模式是一种确保某一类只有一个实例存在的模式。它在许多场景中发挥着重要作用,例如,当我们想要创建一个全局变量或对象时,单例模式就派上了用场。

在Go语言中,我们可以使用sync.Once类型来轻松实现单例模式。sync.Once类型提供了一个Do方法,该方法只会在第一次调用时执行,之后再调用将不会有任何效果。

package main

import (
    "sync"
    "fmt"
)

type Singleton struct {
    // ...
}

var (
    instance *Singleton
    once sync.Once
)

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

func main() {
    s1 := GetInstance()
    s2 := GetInstance()
    fmt.Println(s1 == s2) // 输出:true
}

2. 工厂模式

工厂模式是一种创建对象而不指定具体类的模式。它允许我们根据不同的条件创建不同的对象,从而提高代码的可重用性。

在Go语言中,我们可以使用interface{}type assertion来实现工厂模式。

package main

import (
    "fmt"
)

type Shape interface {
    Draw()
}

type Circle struct {
    // ...
}

func (c *Circle) Draw() {
    fmt.Println("Draw a circle")
}

type Square struct {
    // ...
}

func (s *Square) Draw() {
    fmt.Println("Draw a square")
}

func CreateShape(shapeType string) Shape {
    switch shapeType {
    case "circle":
        return &Circle{}
    case "square":
        return &Square{}
    default:
        return nil
    }
}

func main() {
    circle := CreateShape("circle")
    circle.Draw() // 输出:Draw a circle

    square := CreateShape("square")
    square.Draw() // 输出:Draw a square
}

3. 策略模式

策略模式是一种将算法或行为封装成独立的类,从而使算法或行为可以随时更换的模式。它可以提高代码的灵活性,降低耦合度。

在Go语言中,我们可以使用interface{}type assertion来实现策略模式。

package main

import (
    "fmt"
)

type SortStrategy interface {
    Sort([]int)
}

type BubbleSort struct {
    // ...
}

func (b *BubbleSort) Sort(nums []int) {
    // ...
}

type QuickSort struct {
    // ...
}

func (q *QuickSort) Sort(nums []int) {
    // ...
}

func Sort(nums []int, strategy SortStrategy) {
    strategy.Sort(nums)
}

func main() {
    nums := []int{5, 3, 1, 2, 4}

    bubbleSort := &BubbleSort{}
    Sort(nums, bubbleSort)
    fmt.Println(nums) // 输出:[1 2 3 4 5]

    quickSort := &QuickSort{}
    Sort(nums, quickSort)
    fmt.Println(nums) // 输出:[1 2 3 4 5]
}

4. 观察者模式

观察者模式是一种当一个对象的状态发生变化时,所有依赖它的对象都会收到通知的模式。它可以实现对象之间的松散耦合,提高代码的可维护性。

在Go语言中,我们可以使用sync.Mapchannel来实现观察者模式。

package main

import (
    "sync"
    "fmt"
)

type Subject struct {
    observers sync.Map
    state     int
}

func (s *Subject) Attach(observer interface{}) {
    s.observers.Store(observer, struct{}{})
}

func (s *Subject) Detach(observer interface{}) {
    s.observers.Delete(observer)
}

func (s *Subject) Notify() {
    s.observers.Range(func(key, value interface{}) bool {
        fmt.Println("Notifying observer:", key)
        return true
    })
}

func (s *Subject) SetState(state int) {
    s.state = state
    s.Notify()
}

type Observer struct {
    id int
}

func (o *Observer) Update(subject *Subject) {
    fmt.Println("Observer", o.id, "notified, state:", subject.state)
}

func main() {
    subject := &Subject{}

    observer1 := &Observer{1}
    subject.Attach(observer1)

    observer2 := &Observer{2}
    subject.Attach(observer2)

    subject.SetState(1) // 输出:Notifying observer: 1, state: 1
                         //        Notifying observer: 2, state: 1

    subject.SetState(2) // 输出:Notifying observer: 1, state: 2
                         //        Notifying observer: 2, state: 2
}

上述仅仅只是23种设计模式中的冰山一角,要想真正掌握设计模式,需要不断地练习和积累经验。在实际开发中,设计模式并不是万能的,需要根据具体情况灵活运用,才能发挥出它的最大价值。