Go语言实现GoF设计模式的源码解析

Go语言实现GoF设计模式的源码解析 大家好! 出于学习目的,我正在研究Go源代码/实现本身中的设计模式[GoF]。由于我是Go语言的新手,而且它不是那种带有继承和类等概念的常见面向对象语言,因此我很难找到一些模式。那么……有人知道在哪里可以找到源代码中的设计模式吗?

5 回复

GoF模式有很多。正如你已经注意到的,由于Go实现面向对象编程的方式,创建型和结构型模式很难找到。

但还有行为型模式。你能识别出其中的一些吗?


你说得对,我明白你的意思了。我确实看了一下教授给我们的列表,并且真的从中找到了一些。Go语言在其mchaches中使用了缓存旁路模式。此外,我注意到在堆分配和跨度方面,有类似对象池模式的东西。另外两个是垃圾收集器和锁定模式,我之前并不知道这些实际上也被视为设计模式。

感谢您的回答,遗憾的是我还没有找到任何,但也许观察者模式被用于信号/通知或使用通道的异步/等待模式……我仍在努力寻找。

系统编程中需要关注的问题与应用程序编程中需要注意的问题是不同的。

在进行系统编程时,通常,原始性能本身就是一个要求。在这些情况下,可能会看到一些表面上忽略软件开发实践的非传统代码。这种情况下的原因是,目标是要榨取原始性能的最后一滴,并且要非常小心内存分配。

另一方面,在应用程序开发过程中,目标是尽可能贴近我们领域空间的通用语言,并在我们的解决方案空间中尽可能清晰地表达它。在这里应用设计模式和架构模式更有意义。在进行应用程序开发的过程中,原始性能并不像在系统编程中那样关键。

因此,我认为我们不应该期望在Go语言本身的源代码中看到太多这些设计和实践。

在Go标准库和运行时中可以找到多种GoF设计模式的实现。以下是几个典型示例:

1. 单例模式 (Singleton)

// sync.Once 是实现单例的典型方式
package main

import (
    "fmt"
    "sync"
)

type config struct {
    apiKey string
}

var (
    instance *config
    once     sync.Once
)

func GetConfig() *config {
    once.Do(func() {
        instance = &config{apiKey: "secret-key"}
    })
    return instance
}

func main() {
    c1 := GetConfig()
    c2 := GetConfig()
    fmt.Println(c1 == c2) // true
}

2. 工厂模式 (Factory)

// net/http 包中的 Transport 工厂
package main

import (
    "net/http"
    "net/http/httptest"
)

func createTestServer() *httptest.Server {
    return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
    }))
}

func main() {
    server := createTestServer()
    defer server.Close()
}

3. 装饰器模式 (Decorator)

// io 包中的 MultiReader 是装饰器模式的实现
package main

import (
    "io"
    "strings"
)

func decorateReader(r io.Reader) io.Reader {
    prefix := strings.NewReader("PREFIX: ")
    suffix := strings.NewReader(" :SUFFIX\n")
    return io.MultiReader(prefix, r, suffix)
}

func main() {
    data := strings.NewReader("main content")
    decorated := decorateReader(data)
    io.Copy(io.Discard, decorated)
}

4. 观察者模式 (Observer)

// context 包中的取消机制体现了观察者模式
package main

import (
    "context"
    "fmt"
    "time"
)

func worker(ctx context.Context, name string) {
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("%s: received cancellation\n", name)
            return
        default:
            fmt.Printf("%s: working\n", name)
            time.Sleep(500 * time.Millisecond)
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    
    go worker(ctx, "worker1")
    go worker(ctx, "worker2")
    
    time.Sleep(2 * time.Second)
    cancel()
    time.Sleep(1 * time.Second)
}

5. 策略模式 (Strategy)

// sort 包中的 Interface 体现了策略模式
package main

import (
    "fmt"
    "sort"
)

type ByLength []string

func (s ByLength) Len() int           { return len(s) }
func (s ByLength) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s ByLength) Less(i, j int) bool { return len(s[i]) < len(s[j]) }

func main() {
    fruits := []string{"peach", "banana", "kiwi"}
    sort.Sort(ByLength(fruits))
    fmt.Println(fruits) // [kiwi peach banana]
}

6. 适配器模式 (Adapter)

// http.HandlerFunc 是函数到接口的适配器
package main

import (
    "fmt"
    "net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World")
}

func main() {
    // 函数适配为 http.Handler 接口
    var handler http.Handler = http.HandlerFunc(helloHandler)
    _ = handler
}

这些示例展示了Go语言通过接口、组合和函数式编程等方式实现传统设计模式。Go标准库中还有更多模式实现,如sync.Pool(对象池模式)、bufio.Scanner(迭代器模式)等。

回到顶部