小插曲:
一猎头拉了个几百人的微信群,主要是沈阳、大连从事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 <Windows.h>
#include <iostream>
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/