Go代码模板-单例模式

后端 / 笔记 / 2023-02-23

写在前面

在平时开发中,我们用到最多的 可能就是单例模式了。

什么? 你问我单例模式是啥子??

A: 你平时是怎么创建对象 的。
B: 我还没对象呢,我怎么知道。

A: 怎么可能,没对象你写什么Go?
B: 我是写C的

A: 写C的 gcc


开个玩笑。 其实 单例模式说白就是我们的对象实例在整个程序生命周期中只存在一个。

通常在 Java 中 我们将一个 静态变量 instance 初始 赋值成一个 null 然后每次判断的时候 只需要判断 是不是为空 如果为空 就初始化。通过这样的手段来实现单例模式哦。

such as ...

public class Singleton {

    private static Singleton instance;

    private Singleton() {
        // private constructor to prevent instantiation from outside
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

虽然在go中也可以通过这样的方式实现。 但是 显得我们一点都不Gopher

那就不卖关子了,直接上才艺:

package service

import "sync"

type MessageService interface {
}

type messageService struct {
}

var ins MessageService
var messageServiceOnce = sync.Once{}

func NewMessageService() MessageService {
	messageServiceOnce.Do(func() {
		ins = &messageService{}
	})
	return ins
}

wtf? 居然还可以这样写? 你这写的 我也没看出有多大的作用啊。

不对

  1. sync.Once 这是啥
  2. 为什么要用一个接口
  3. 这个 ins 又是啥

别急听我 一一道来。

  1. sync.Once 是 go 标准库中提供的一个 结构体。 通过 Do 方法我们可以保证 里面的 函数 只初始化一次
  2. 为什么要用接口? 这种话你也问的出? 我.... 当然是为了 延迟决策 永远不要将业务方法过绑定到结构体上,这里我们用interface 巧妙解决了这个问题 假设现在我们用的 service 是一套方案。 突然某一天有了新的需求 但是 现有代码很难维护,我们不得不去 修改原有业务逻辑。 风险指数级提升。 但是通过 interface 就很大程度上避免了和这个问题。 即便我们后期替换框架 只需要 重新实现下 interface ,然后直接替换 而无需变动上层调用代码。 既保留了 原来的 狮山 也实现了新特性。
  3. ins? 当然是 instance 啊 就是一个 实例

小结

  • sync.Once 可以让你的代码 更 Gopher
  • 通过 interface 延迟绑定
  • 不要将业务逻辑绑定到某一个具体的结构体上
  • 尽可能的延迟决策