概述
单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式分为懒汉式和饿汉式
饿汉式:当一个类在引入或加载时,实例就创建并初始化。
优点:
- 提前创建好实例,避免在程序运行的时候,再去初始化导致的性能问题。
- 按照 fail-fast 的设计原则(有问题及早暴露),有问题时初始化就能暴(比如内存溢出),不用等到线上运行时,影响系统可用性。
缺点:
- 初始化资源耗时,如果需要初始化的对象很多,程序加载时间太久,体验不好。
- 资源效率不高,实例初始化出来后可能一直没有使用到,造成浪费
懒汉式:延迟加载,只有在实例需要使用时,才初始化实例。
- 优缺点与饿汉式相反
Python
1.饿汉模式
当一个类在引入或加载时,实例就创建并初始化。
在类被加载时就将自己实例化(静态初始化)。优点是躲避了多线程的安全性问题,缺点是提前占用系统资源
python模块就已经是单例模式了, 但这不是面向对象,而是模块的数据,变量或者全局对象
# 建立一个类
class Log:
pass
# 再模块种实例化这个类,这样其他模块引入此模块中的实例时,就实现了单例模式
# 其他模块通过 import log 使用实例
log = Log()
2.懒汉模式
在第一次被引用时才将自己实例化。避免开始时占用系统资源,但是有多线程访问安全性问题
# 一般用new方法
# 基类
class Singleton:
# 设置一个静态变量,用来保证实例的唯一性
# _instance = None # 添加此行会出错:AttributeError: 'NoneType' object has no attribute 'a'
def __new__(cls, *args, **kwargs):
# 用一个类属性来表示类的实例,如果类已经有这个属性(实例)了,就直接返回实例,如果没有再创建
if not hasattr(cls, "_instance"):
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
# 继承类(实现单例模式效果的类),想要把这个类设置成为单例的类,就去继承单例类这个基类,也就继承了new方法
class MyClass(Singleton):
def __init__(self, a):
self.a = a
# 创建一个MyClass的对象
a = MyClass(10) # 首次实例化这个单例类
b = MyClass(20) # 再次实例化这个类 -结果会变为新实例化时的值-
# 验证
print(a.a) # 20
print(b.a) # 20
print(id(a),id(b)) # id相同,同一个实例
'''
用到单例模式的场景:希望这个实例最好只出现一次
比如写一个web框架,这个框架有一个日志系统,这个日志对象只能有一个,不能两个日志对象同时操作一个同一个文件,不然会出现冲突
数据库连接池连接器,也最好做成单例的,不能建立多个数据库连接
操作系统的文件系统
'''
双重检测
饿汉式不支持延迟加载,懒汉式有性能问题,不支持高并发。有一种既支持延迟加载、又支持高并发的单例实现方式,也就是双重检测实现方式。
通过双重检测方式,我们要保证同一时刻,多个线程只有一个能够操作实例的创建,我们可以通过多线程锁来实现。只要实例被创建之后,即便再调用 get_instance 函数也不会再进入到加锁逻辑中了
具体实例如下:
from threading import Lock
class Singleton:
"""
通过一个多线程锁保证同一时刻最多只有一个线程能创建实例
不能通过 new 方法创建实例
"""
# 线程锁
_lock = Lock()
def __new__(cls, *args, **kwargs):
msg = "Cann't new a SingletonSample class, please use get_instance method!"
raise NotImplementedError(msg)
# 静态方法
@classmethod
def get_instance(cls):
if not hasattr(cls, "_instance"):
with cls._lock:
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls)
return cls._instance
JavaScript
单例模式的思路是:保证一个类只能被实例一次,每次获取的时候,如果该类已经创建过实例则直接返回该实例,否则创建一个实例保存并返回。
单例模式的核心就是创建一个唯一的对象,而在javascript中创建一个唯一的对象太简单了,为了获取一个对象而去创建一个类有点多此一举。如const obj = {},obj就是独一无二的一个对象,在全局作用域的声明下,可以在任何地方对它访问,这就满足了单例模式的条件。
我们常见到的登录弹窗,要么显示要么隐藏,不可能同时出现两个弹窗,下面我们通过一个类来模拟弹窗。
class LoginFrame {
static instance = null
constructor(state){
this.state = state
}
show(){
if(this.state === 'show'){
console.log('登录框已显示')
return
}
this.state = 'show'
console.log('登录框展示成功')
}
hide(){
if(this.state === 'hide'){
console.log('登录框已隐藏')
return
}
this.state = 'hide'
console.log('登录框隐藏成功')
}
// 通过静态方法获取静态属性instance上是否存在实例,如果没有创建一个并返回,反之直接返回已有的实例
static getInstance(state){
if(!this.instance){
this.instance = new LoginFrame(state)
}
return this.instance
}
}
const p1 = LoginFrame.getInstance('show')
const p2 = LoginFrame.getInstance('hide')
console.log(p1 === p2) // true
总结
以上就是单例模式的几种实现方法,除了以上的几种实现方法,还有其他各种各样的实现方法,重要的是能够理解其实现原理和思路。
最后
以上就是健壮小鸭子为你收集整理的【笔记整理】23种设计模式——单例模式单例模式总结的全部内容,希望文章能够帮你解决【笔记整理】23种设计模式——单例模式单例模式总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复