Golang視角下的設計模式

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

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

單例模式:

Gloang的單例模式該怎麼寫?隨手寫一個,不錯,立馬寫出來了。但這個代碼有什麼問題呢?多個協程同時執行這段代碼就會出現問題:instance可能會被賦值多次,這段代碼是線程不安全的代碼。那麼如何保證在多線程下只執行一次呢?條件反射:加鎖。。。加鎖是可以解決問題。但不是最優的方案,因為如果有1W並發,每一個線程都競爭鎖,同一時刻只有一個線程能拿到鎖,其他的全部阻塞等待。讓原本想並發得飛起來變成了一切認慫序列化。通過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}

原廠模式:

工廠根據條件產生不同功能的類。原廠模式使用經常使用在替代new的情境中,讓工廠統一根據不同條件生產不同的類。原廠模式在解耦方面將使用者和產品之間的依賴推給了工廠,讓工廠承擔這種依賴關係。原廠模式又分為簡單工廠,抽象工廠。golang實現一個簡單原廠模式如下:

package mainimport (    "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())}

依賴注入:

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

package mainimport (    "fmt"    "reflect")var inj *Injectortype Injector struct {    mappers map[reflect.Type]reflect.Value // 根據類型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() {    // 建立注入器    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)}

裝飾器模式:

裝飾器模式:允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是作為現有的類的一個封裝。這種模式建立了一個裝飾類,用來封裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。我們使用最為頻繁的情境就是http請求的處理:對http請求做cookie校正。

package mainimport (    "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中是如何體現出來的,架構或者類庫應該是設計模式常常出沒的地方。深入理解設計模式有助於代碼的抽象,複用和解耦,讓代碼與代碼之間更加低耦合。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.