Go实战--Design Patterns in Golang 之单利模式(Singleton)

小插曲:

一猎头拉了个几百人的微信群,主要是沈阳、大连从事IT工作的人,以下是某几个时段的聊天截图:




回不去的东北……很多同事都说如果我选择回东北,肯定后悔,用不了多久还会回北京。

生命不止,继续 go go go !!!

golang的基础知识介绍了很多很多了,主要是一些官方package的介绍。
golang的实战也介绍了很多很多了,包括了很多web框架,rest api,操作各种类型的数据库,各种认证方式,等等等。

接下来,就要跟大家一起学习,分享golang中的设计模式了。

PS: 设计模式的重要性不用多说,也是面试官常常问到的问题。但是对于设计模式,更多的是仁者见仁智者见智。要在实际工作中,代码的积累,工程的积累,再进行深度的思考,逐渐形成的一种思维。

Patterns,顾名思义,具有某种重复性规律的方案。Design Patterns,就是设计过程中可以反复使用的、可以解决特定问题的设计方法。

当然,是从最普遍,最简单的单利模式入手了。

何为单例

wiki:
In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object.

举个栗子:
Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。这就可以使用单例模式来解决该问题。

C++中实现单例:

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {}                    // Constructor? (the {} brackets) are needed here.

        // C++ 03
        // ========
        // Don't forget to declare these two. You want to make sure they
        // are unacceptable otherwise you may accidentally get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement

        // C++ 11
        // =======
        // We can use the better technique of deleting the methods
        // we don't want.
    public:
        S(S const&)               = delete;
        void operator=(S const&)  = delete;

        // Note: Scott Meyers mentions in his Effective Modern
        //       C++ book, that deleted functions should generally
        //       be public as it results in better error messages
        //       due to the compilers behavior to check accessibility
        //       before deleted status
};

把构造函数作为私有。

c++实现单例完整栗子:

#include 
#include 

using namespace std;


class SingletonClass {

public:
    static SingletonClass* getInstance() {

    return (!m_instanceSingleton) ?
        m_instanceSingleton = new SingletonClass : 
        m_instanceSingleton;
    }

private:
    // private constructor and destructor
    SingletonClass() { cout << "SingletonClass instance created!\n"; }
    ~SingletonClass() {}

    // private copy constructor and assignment operator
    SingletonClass(const SingletonClass&);
    SingletonClass& operator=(const SingletonClass&);

    static SingletonClass *m_instanceSingleton;
};

SingletonClass* SingletonClass::m_instanceSingleton = nullptr;



int main(int argc, const char * argv[]) {

    SingletonClass *singleton;
    singleton = singleton->getInstance();
    cout << singleton << endl;

    // Another object gets the reference of the first object!
    SingletonClass *anotherSingleton;
    anotherSingleton = anotherSingleton->getInstance();
    cout << anotherSingleton << endl;

    Sleep(5000);

    return 0;
}

golang中的单例

但是,在golang的世界中,没有private public static等关键字,也没有面向对象中类的概念。

那么golang是如何控制访问范围的呢?
首字母大写,代表对外部可见,首字母小写代表对外部不可见,适用于所有对象,包括函数、方法

golang中全局变量
可以使用全局变量,达到c++中static的效果

golang标准库中的单例模式使用示例
golang是开源的,当我们不知道怎么写代码的时候,完全可以读一读golang的源码。
对于单例模式,例如net/http包中的 http.DefaultClient 和 http.DefaultServeMux。

  • http.DefaultClient
type Client struct {

    Transport RoundTripper

    CheckRedirect func(req *Request, via []*Request) error

    Jar CookieJar

    Timeout time.Duration
  }
var DefaultClient = &Client{}
  • http.DefaultServeMux
// DefaultServeMux is the default ServeMux used by Serve.
  var DefaultServeMux = &defaultServeMux

golang中单例实现(不完美)
先看代码:

package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

func New() *single {
        if instantiated == nil {
                instantiated = new(single);
        }
        return instantiated;
}

看似不错,但是不是线程安全的。

golang中线程安全的单例模式

使用了sync包:
func (*Once) Do

func (o *Once) Do(f func())

Do calls the function f if and only if Do is being called for the first time for this instance of Once

package singleton

import "sync"

type single struct {
        O interface{};
}

var instantiated *single
var once sync.Once

func New() *single {
        once.Do(func() {
                instantiated = &single{}
        })
        return instantiated
}

单例模式操作数据库

package db

import "fmt"

type repository struct {
    items map[string]string
    mu    sync.RWMutex
}

func (r *repository) Set(key, data string) {
    r.mu.Lock()
    defer r.mu.Unlock()
    r.items[key] = data
}

func (r *repository) Get(key string) (string, error) {
    r.mu.RLock()
    defer r.mu.RUnlock()
    item, ok := r.items[key]
    if !ok {
        return "", fmt.Errorf("The '%s' is not presented", key)
    }
    return item, nil
}

var (
    r    *repository
    once sync.Once
)

func Repository() *repository {
    once.Do(func() {
        r = &repository{
            items: make(map[string]string),
        }
    })

    return r
}

参考:
http://blog.ralch.com/tutorial/design-patterns/golang-singleton/

你可能感兴趣的:(go,Go从不放弃到实战)