Golang視角下的設計模式

這篇文章想聊聊Golang語言下的設計模式問題,我覺得這個話題還是比較有意思的。Golang沒有像java那樣對設計模式瘋狂的迷戀,而是擺出了一份“看庭前花開花落,望天空云卷云舒”的姿態(tài)。

單例模式:

Golang的單例模式該怎么寫?隨手寫一個,不錯,立馬寫出來了。但這個代碼有什么問題呢?多個協(xié)程同時執(zhí)行這段代碼就會出現(xiàn)問題:instance可能會被賦值多次,這段代碼是線程不安全的代碼。那么如何保證在多線程下只執(zhí)行一次呢?條件反射:加鎖。。。加鎖是可以解決問題。但不是最優(yōu)的方案,因為如果有1W并發(fā),每一個線程都競爭鎖,同一時刻只有一個線程能拿到鎖,其他的全部阻塞等待。讓原本想并發(fā)得飛起來變成了一切認慫串行化。通過check-lock-check方式可以減少競爭。還有其他方式,利用sync/atomicsync/once 這里只給出代碼

func NewSingleton() *singleton {
    if instance == nil {
         instance = &singleton{}
    }
    return instance
}
func NewSingleton() *singleton {
    l.Lock()                   // lock
    defer l.Unlock()
    if instance == nil {  // check
        instance = &singleton{}
    }
    return instance
}
func NewSingleton() *singleton {
    if instance == nil {    // check
        l.Lock()            // lock
        defer l.Unlock()   
        if instance == nil {    // check
            instance = &singleton{}
        }
    }
    return instance
}
func NewSingleton() *singleton {
    if atomic.LoadUInt32(&initialized) == 1 {
        return instance
    }
    mu.Lock()
    defer mu.Unlock()
    if initialized == 0 {
        instance = &singleton{}
        atomic.StoreUint32(&initialized, 1)
    }
    return instance
}
func NewSingleton() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

工廠模式:

工廠根據(jù)條件產生不同功能的類。工廠模式使用經(jīng)常使用在替代new的場景中,讓工廠統(tǒng)一根據(jù)不同條件生產不同的類。工廠模式在解耦方面將使用者和產品之間的依賴推給了工廠,讓工廠承擔這種依賴關系。工廠模式又分為簡單工廠,抽象工廠。golang實現(xiàn)一個簡單工廠模式如下:

package main
import (
    "fmt"
)
type Op interface {
    getName() string
}
type A struct {
}
type B struct {
}
type Factory struct {
}
func (a *A) getName() string {
    return "A"
}
func (b *B) getName() string {
    return "B"
}
func (f *Factory) create(name string) Op {
    switch name {
    case `a`:
        return new(A)
    case `b`:
        return new(B)
    default:
        panic(`name not exists`)
    }
    return nil
}
func main() {
    var f = new(Factory)
    p := f.create(`a`)
    fmt.Println(p.getName())
    p = f.create(`b`)
    fmt.Println(p.getName())
}

依賴注入:

具體含義是:當某個角色(可能是一個實例,調用者)需要另一個角色(另一個實例,被調用者)的協(xié)助時,在傳統(tǒng)的程序設計過程中,通常由調用者來創(chuàng)建被調用者的實例。但在這種場景下,創(chuàng)建被調用者實例的工作通常由容器(IoC)來完成,然后注入調用者,因此也稱為依賴注入。
Golang利用函數(shù)f可以當做參數(shù)來傳遞,同時配合reflect包拿到參數(shù)的類型,然后根據(jù)調用者傳來的參數(shù)和類型匹配上之后,最后通過reflect.Call()執(zhí)行具體的函數(shù)。下面的代碼來自:https://www.studygolang.com/articles/4957 這篇文章上。

package main

import (
    "fmt"
    "reflect"
)

var inj *Injector

type Injector struct {
    mappers map[reflect.Type]reflect.Value // 根據(jù)類型map實際的值
}

func (inj *Injector) SetMap(value interface{}) {
    inj.mappers[reflect.TypeOf(value)] = reflect.ValueOf(value)
}

func (inj *Injector) Get(t reflect.Type) reflect.Value {
    return inj.mappers[t]
}

func (inj *Injector) Invoke(i interface{}) interface{} {
    t := reflect.TypeOf(i)
    if t.Kind() != reflect.Func {
        panic("Should invoke a function!")
    }
    inValues := make([]reflect.Value, t.NumIn())
    for k := 0; k < t.NumIn(); k++ {
        inValues[k] = inj.Get(t.In(k))
    }
    ret := reflect.ValueOf(i).Call(inValues)
    return ret
}

func Host(name string, f func(a int, b string) string) {
    fmt.Println("Enter Host:", name)
    fmt.Println(inj.Invoke(f))
    fmt.Println("Exit Host:", name)
}

func Dependency(a int, b string) string {
    fmt.Println("Dependency: ", a, b)
    return `injection function exec finished ...`
}

func main() {
    // 創(chuàng)建注入器
    inj = &Injector{make(map[reflect.Type]reflect.Value)}
    inj.SetMap(3030)
    inj.SetMap("zdd")

    d := Dependency
    Host("zddhub", d)

    inj.SetMap(8080)
    inj.SetMap("www.zddhub.com")
    Host("website", d)
}

裝飾器模式:

裝飾器模式:允許向一個現(xiàn)有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬于結構型模式,它是作為現(xiàn)有的類的一個包裝。這種模式創(chuàng)建了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。我們使用最為頻繁的場景就是http請求的處理:對http請求做cookie校驗。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func autoAuth(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        cookie, err := r.Cookie("Auth")
        if err != nil || cookie.Value != "Authentic" {
            w.WriteHeader(http.StatusForbidden)
            return
        }
        h(w, r)
    }
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World! "+r.URL.Path)
}

func main() {
    http.HandleFunc("/hello", autoAuth(hello))
    err := http.ListenAndServe(":5666", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

還有很多其他模式,這里不一一給出了,寫這篇文章的目的是想看看這些模式在golang中是如何體現(xiàn)出來的,框架或者類庫應該是設計模式常常出沒的地方。深入理解設計模式有助于代碼的抽象,復用和解耦,讓代碼與代碼之間更加低耦合。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評論 25 708
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,853評論 18 399
  • 在生活或者工作中,我們經(jīng)常會為了給別人留下一個好的印象,去做一些事情。比如面試,在面試之前我們得做好充足的準備,給...
    小小青橙閱讀 371評論 0 2
  • 標題很奇怪吧。怎么會有人不喜歡喜歡的人呢? 偶然間在微博里看到一種病,別人不喜歡你的時候你千方百計地靠近他,想得到...
    再美劇本也有劇終時閱讀 311評論 0 0
  • 你靜靜的 讓夜色吞噬 找不到 對你眨眼的星星 也找不到 那片微笑的云 孤寂 是素色的靈魂 曾牽引著 疲憊的腳步 漫...
    饅頭兒閱讀 383評論 1 1

友情鏈接更多精彩內容