1.说明
前面5篇文章讲解了设计模式的语法、面向对象分析、原则、代码编写、类图表示法,从本文开始讲述23种设计模式。
后面会按照创建型、结构型、行为型的顺序来写
- 创建型5个:单例模式、简单工厂、工厂模式、建造者模式、原型模式 ,主要解决“对象的创建”问题
- 结构型7:代理模式、桥接模式、装饰器模式、适配器模式、门面模式 、组合模式、享元模式,主要解决“类或对象的组合或组装”问题
- 行为型11:观察者模式、模板模式、策略模式、职责链模式、状态模式、迭代器模式、访问者模式、备忘录模式、命令模式、解释器模式、中介模式,主要解决“类或对象之间的交互”问题
有7个模式并不太常用,他们分别是:组合模式、享元模式、状态模式、访问者模式、命令模式、解释器模式、中介模式,所以常用的设计模式16个。
每篇文章尽量都会有类图、定义、分析、使用场景、实现、代码、扩展等信息。之所以包含这些信息,因为对于很多人来说,你问他个具体的设计原则、思想、模式的原理和实现,他都能回答得头头是道,但是,在实际的项目开发中,写出来的代码质量还是很差。这种情况出现的原因还是,相关的知识点都过于抽象,通俗点讲就是有点“假大空”,不够具体、不太能落地,所以导致理论和实践容易脱节。
2.定义
2.1单例模式
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
UML类图:链接为https://www.processon.com/view/link/6080def6079129456d4beecf
2.2分析
通过分析能够看出以下几点:
- 单例模式能够保证类只有一个实例,就是类图里的instance
- 有方法能够让外部访问到该实例,就是类图里的GetInstance
- 外部无法创建实例,是因为构造函数为私有函数,外部无法访问,自然也就无法生成实例
3.使用场景
单例模式理解相对简单,一般在哪些场景下我们会用到单例模式呢?
多线程情况下会导致资源访问冲突
- 如项目需要写Log,而且Log一般会写入同一个文件。如果存在多个Log对象,即使Log有对象级别的锁,但在多线程下完全无用,日志仍然会乱序。解决这个问题我们可以使用类级别锁、分布式锁,但是都相对麻烦一些。如果使用单例模式,则Log只需保持对象级别锁就可以解决资源访问冲突
需要保证全局唯一的类
- 比如配置类,这种只应该存在一份
4.代码
单例模式的实现的时候需要考虑如下问题:
- 对象创建时线程安全问题
- 是否支持延迟加载
- 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()
}
关于代码,此处说明几点:
- 使用sync.Once.Do,轻松解决线程安全问题,确保只会有一个实例
- singleTon类首字母需要小写,这样能够保证非design的包无法创建单例类。如下图所示,main包无法获取到singleTon类
- 此处的实现方式是懒汉式,如果想使用饿汉式,可以使用init或者项目启动初始化时直接调用,具体实现大家可自己完成
- 具体代码可以查看:https://github.com/shidawuhen/asap/blob/master/controller/design/6single.go
5.总结
单例模式作为简单、常用的模式是一定需要掌握的。但单例模式也有一些缺点,如在继承、多态方面能力会弱一些,是否使用单例模式需要依据具体情况而定。另外单例模式也可以扩展到集群环境下、可以扩展为多例模式,这些内容大家有兴趣可以研究一下。
最后
大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)
我的个人博客为:https://shidawuhen.github.io/
往期文章回顾:
招聘
设计模式
语言
架构
存储
网络
工具
读书笔记
思考