Go设计模式(6)-单例模式

1.说明

前面5篇文章讲解了设计模式的语法、面向对象分析、原则、代码编写、类图表示法,从本文开始讲述23种设计模式。

后面会按照创建型、结构型、行为型的顺序来写

  1. 创建型5个:单例模式、简单工厂、工厂模式、建造者模式、原型模式 ,主要解决“对象的创建”问题

  2. 结构型7:代理模式、桥接模式、装饰器模式、适配器模式、门面模式 、组合模式、享元模式,主要解决“类或对象的组合或组装”问题

  3. 行为型11:观察者模式、模板模式、策略模式、职责链模式、状态模式、迭代器模式、访问者模式、备忘录模式、命令模式、解释器模式、中介模式,主要解决“类或对象之间的交互”问题

有7个模式并不太常用,他们分别是:组合模式、享元模式、状态模式、访问者模式、命令模式、解释器模式、中介模式,所以常用的设计模式16个。

每篇文章尽量都会有类图、定义、分析、使用场景、实现、代码、扩展等信息。之所以包含这些信息,因为对于很多人来说,你问他个具体的设计原则、思想、模式的原理和实现,他都能回答得头头是道,但是,在实际的项目开发中,写出来的代码质量还是很差。这种情况出现的原因还是,相关的知识点都过于抽象,通俗点讲就是有点“假大空”,不够具体、不太能落地,所以导致理论和实践容易脱节。

2.定义

2.1单例模式

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

UML类图:链接为https://www.processon.com/view/link/6080def6079129456d4beecf

image-20210420131156614.png

2.2分析

通过分析能够看出以下几点:

  1. 单例模式能够保证类只有一个实例,就是类图里的instance
  2. 有方法能够让外部访问到该实例,就是类图里的GetInstance
  3. 外部无法创建实例,是因为构造函数为私有函数,外部无法访问,自然也就无法生成实例

3.使用场景

单例模式理解相对简单,一般在哪些场景下我们会用到单例模式呢?

  1. 多线程情况下会导致资源访问冲突
    • 如项目需要写Log,而且Log一般会写入同一个文件。如果存在多个Log对象,即使Log有对象级别的锁,但在多线程下完全无用,日志仍然会乱序。解决这个问题我们可以使用类级别锁、分布式锁,但是都相对麻烦一些。如果使用单例模式,则Log只需保持对象级别锁就可以解决资源访问冲突
  2. 需要保证全局唯一的类
    • 比如配置类,这种只应该存在一份

4.代码

单例模式的实现的时候需要考虑如下问题:

  1. 对象创建时线程安全问题
  2. 是否支持延迟加载
  3. getInstance()性能是否高

根据语言不同,实现方式也不一样,一般有饿汉式、懒汉式、双重检测、静态内部类、枚举等。无论使用哪种方式,核心目的都是为了只会生成一个实例

这里多少解释一下饿汉式和懒汉式。饿汉式可以简单的理解为实例提前创建好了,getInstance只是获取实例返回。懒汉式是调用getInstance的时候,getInstance负责生成唯一实例。两者各有优缺点,饿汉式不必考虑线程安全问题,实例生成的成本放在项目启动时,但不支持延迟加载;懒汉式需要考虑线程安全问题,支持延迟加载。

具体实现以前在文章Go单例实现方案中写过,实现方式比较简单

/**
@date: 2021/4/22
单例模式
**/
package design

import (
	"fmt"
	"sync"
)

type singleTon struct {
}

func (s *singleTon) Show() {
	fmt.Println("hello world")
}

var (
	once   sync.Once
	single *singleTon
)

func GetSingleInstance() *singleTon {
	once.Do(func() {
		single = &singleTon{}
	})
	return single
}
func main() {
	single := design.GetSingleInstance()
	single.Show()
}

关于代码,此处说明几点:

  1. 使用sync.Once.Do,轻松解决线程安全问题,确保只会有一个实例
  2. singleTon类首字母需要小写,这样能够保证非design的包无法创建单例类。如下图所示,main包无法获取到singleTon类

image-20210422094017975.png
3. 此处的实现方式是懒汉式,如果想使用饿汉式,可以使用init或者项目启动初始化时直接调用,具体实现大家可自己完成
4. 具体代码可以查看:https://github.com/shidawuhen/asap/blob/master/controller/design/6single.go

5.总结

单例模式作为简单、常用的模式是一定需要掌握的。但单例模式也有一些缺点,如在继承、多态方面能力会弱一些,是否使用单例模式需要依据具体情况而定。另外单例模式也可以扩展到集群环境下、可以扩展为多例模式,这些内容大家有兴趣可以研究一下。

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

往期文章回顾:

招聘

  1. 字节跳动|抖音电商服务端技术岗位虚位以待
  2. 字节跳动招聘专题

设计模式

  1. Go设计模式(5)-类图符号表示法
  2. Go设计模式(4)-代码编写优化
  3. Go设计模式(4)-代码编写
  4. Go设计模式(3)-设计原则
  5. Go设计模式(2)-面向对象分析与设计
  6. Go设计模式(1)-语法

语言

  1. Go工具之generate
  2. Go单例实现方案
  3. Go通道实现原理
  4. Go定时器实现原理
  5. Beego框架使用
  6. Golang源码BUG追查
  7. Gin框架简洁版
  8. Gin源码剖析

架构

  1. 支付接入常规问题
  2. 限流实现2
  3. 秒杀系统
  4. 分布式系统与一致性协议
  5. 微服务之服务框架和注册中心
  6. 浅谈微服务
  7. 限流实现1
  8. CDN请求过程详解
  9. 常用缓存技巧
  10. 如何高效对接第三方支付
  11. 算法总结

存储

  1. MySQL开发规范
  2. Redis实现分布式锁
  3. 事务原子性、一致性、持久性的实现原理
  4. InnoDB锁与事务简析

网络

  1. HTTP2.0基础教程
  2. HTTPS配置实战
  3. HTTPS连接过程
  4. TCP性能优化

工具

  1. 根据mysql表自动生成go struct
  2. Markdown编辑器推荐-typora

读书笔记

  1. 原则
  2. 资治通鉴
  3. 敏捷革命
  4. 如何锻炼自己的记忆力
  5. 简单的逻辑学-读后感
  6. 热风-读后感
  7. 论语-读后感
  8. 孙子兵法-读后感

思考

  1. 为动员一切力量争取抗战胜利而斗争
  2. 反对自由主义
  3. 实践论
  4. 评价自己的标准
  5. 服务端团队假期值班方案
  6. 项目流程管理
  7. 对项目管理的一些看法
  8. 对产品经理的一些思考
  9. 关于程序员职业发展的思考
  10. 关于代码review的思考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值