关于golang:手撸golang-创建型设计模式-单例模式

43次阅读

共计 3164 个字符,预计需要花费 8 分钟才能阅读完成。

手撸 golang 创立型设计模式 单例模式

缘起

最近温习设计模式
拜读谭勇德的 << 设计模式就该这样学 >>
本系列笔记拟采纳 golang 练习之

单例模式

单例模式(Singleton Pattern)指确保一个类在任何状况下都相对只有一个实例,并提供一个全局拜访点,属于创立型设计模式。
_

三种常见单例模式

  • 饿汉式单例

    • 类 / 模块初始化时立刻创立的动态全局单例
  • 双重检查单例

    • 提供获取单例的办法
    • 在该办法中通过双重查看动态实例是否为 null, 以提早初始化全局单例
    • 首次查看不加同步锁, 二次查看加同步锁, 以保障单例只创立一次
  • 容器式单例

    • 存在全局惟一的 Bean 容器
    • 通过 Bean 的名称读取或设置与该名称绑定的 bean 单例
    • 通过读写锁管制并发平安
    • 罕用于须要持有大量单例的场景, 如 IOC 容器

单元测试

singleton_test.go, 顺次调用了三种单例的办法

package patterns

import "testing"
import (sg "learning/gooop/creational_patterns/singleton")

func Test_Singleton(t *testing.T) {fnTestSingleton := func(it sg.IDemoSingleton) {it.Hello()
    }

    fnTestSingleton(sg.HungrySingleton)
    fnTestSingleton(sg.GetDualCheckSingleton())

    ok, it := sg.DefaultBeanContaibner.GetBean("IDemoSingleton")
    if ok {fnTestSingleton(it.(sg.IDemoSingleton))
    }
}

测试输入

$ go test -v singleton_test.go 
=== RUN   Test_Singleton
tHungrySingleton.Hello
tDualCheckSingleton.Hello
tContainedSingleton.Hello
--- PASS: Test_Singleton (0.00s)
PASS
ok      command-line-arguments  0.002s

IDemoSingleton.go

定义单例的接口

package singleton

type IDemoSingleton interface {Hello()
}

饿汉式单例

HungrySingleton.go 演示如何实现一个饿汉式单例

package singleton

import ("fmt")

type tHungrySingleton struct {}

func newHungrySingleton() *tHungrySingleton {return &tHungrySingleton{}
}

func (me *tHungrySingleton) Hello() {fmt.Printf("tHungrySingleton.Hello\n")
}

var HungrySingleton IDemoSingleton = newHungrySingleton()

双重检查单例

DualCheckSingleton.go 演示如何创立一个双重检查单例

package singleton

import (
    "fmt"
    "sync"
)

type tDualCheckSingleton struct {}


func newDualCheckSingleton() *tDualCheckSingleton {return &tDualCheckSingleton{}
}


func (me *tDualCheckSingleton) Hello() {fmt.Printf("tDualCheckSingleton.Hello\n")
}

var gDualCheckSingleton IDemoSingleton = nil
var gSingletonLock = new(sync.Mutex)

func GetDualCheckSingleton() IDemoSingleton {
    if gDualCheckSingleton == nil {gSingletonLock.Lock()
        defer gSingletonLock.Unlock()

        if gDualCheckSingleton == nil {gDualCheckSingleton = newDualCheckSingleton()
        }
    }

    return gDualCheckSingleton
}

容器式单例

ContainedSingleton.go 演示如何通过 Bean 容器持有大量 Bean 单例. Bean 容器自身是一个饿汉式单例.

package singleton

import (
    "errors"
    "fmt"
    "sync"
)

type IBeanContainer interface {GetBean(string) (bool, interface{})
    SetBean(string, interface{}) error
}

type tBeanContainer struct {mBeans map[string]interface{}
    mRWMutex *sync.RWMutex
}

func newBeanContainer() *tBeanContainer {
    return &tBeanContainer{mBeans: make(map[string]interface{}, 16),
        mRWMutex: new(sync.RWMutex),
    }
}

func (me *tBeanContainer) GetBean(name string) (bool, interface{}) {me.mRWMutex.RLock()
    defer me.mRWMutex.RUnlock()

    it, ok := me.mBeans[name]
    if ok {return true, it} else {return false, nil}
}

func (me *tBeanContainer) SetBean(name string, it interface{}) error {me.mRWMutex.Lock()
    defer me.mRWMutex.Unlock()

    if _,ok := me.mBeans[name];ok {return errors.New(fmt.Sprintf("bean with name %s already exists", name))
    }
    
    me.mBeans[name] = it
    return nil
}

type tContainedSingleton struct {}

func (me *tContainedSingleton) Hello() {fmt.Printf("tContainedSingleton.Hello\n")
}

func newContainedSingleton() IDemoSingleton {return &tContainedSingleton{}
}


var DefaultBeanContaibner = newBeanContainer()

func init() {DefaultBeanContaibner.SetBean("IDemoSingleton", newContainedSingleton())
}

单例模式小结

单例模式的长处
(1)单例模式能够保障内存里只有一个实例,缩小了内存的开销。
(2)能够防止对资源的多重占用。
(3)单例模式设置全局拜访点,能够优化和共享资源的拜访。
单例模式的毛病
(1)单例模式个别没有接口,扩大艰难。如果要扩大,则除了批改原来的代码,没有第二种路径,违反开闭准则。
(2)在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模仿生成一个新的对象。
(3)单例模式的性能代码通常写在一个类中,如果功能设计不合理,则很容易违反繁多职责准则。

(end)

正文完
 0