大牧絮叨设计模式:单例模式
文章目录
- 1、单例模式概述
- 1.1、 核心组件
- 1.2、 优点缺陷
- 2、 `Java`实现
- 2.1、饿汉式单例模式
- 2.2、 懒汉式单例模式
- 3、 `Python`实现
- 3.1、 单实例操作
- 3.2、 静态方法
- 3.3、 `__new__`魔法方法
- 3.4、 装饰器实现
- 4、 `Go`实现
1、单例模式概述
单例模式(Singleton
)[GOF95
]是一种对象的创建模式,确保系统中使用了单例模式的类型只会存在一个实例对象,通过该对象给系统提供一致性的解决方案。
单例模式管理的类型,常规情况下具备如下特性
- 单例类只能有一个实例
- 单例类必须自己创建属于自己的唯一实例对象。
- 单例类必须给其他调用者提供自己的实例对象。
注意:在项目开发过程中,项目可能会存在需要限定多个实例的情况,所以单例模式是一个基础模式,可以在此模式基础上衍生
多例模式
。
单例实现过程中,根据实例的创建时机区分为饿汉式单例
和 懒汉式单例
两种不同的操作方式,所谓饿汉式
表示在类型定义时在类型中已经创建了对应的实例,其他调用者可以随时调用获取;所谓懒汉式
是在类型定义时定义了单例的实现逻辑,但是只有调用者在使用该单例时,第一次调用时才会发生具体实例化过程,之后再使用过程中该实例就是唯一的提供服务的对象。
1.1、 核心组件
单例模式中,最核心的部分就是当前类型自己,为了符合需求中对于单例的使用要求,通常情况下我们会设计当前类型自己的静态方法来获取该类型的实例,并且当前类型不可实例化(构造方法私有化)。
- 单例类(Singleton Class):单例模式的核心类型,和系统中的业务逻辑紧密关联,实例的创建部分的处理由自身的静态方法完成,对外只暴露包含业务功能的单个实例对象。
1.2、 优点缺陷
单例类的设计通常是基于某些系统功能的要求,一般情况下是基于功能上的限制或者业务上的要求,某一部分功能业务逻辑在整个系统平台的运行周期中,必须是让所有功能模块共享的独立一份,此时单例模式的应用能简单开发过程中的业务逻辑的复杂度,但是注意单例模式并不是唯一的解决方案。
优点
- 能有好的处理系统中独立一份数据的共享和信息传递
- 减少内存开销,避免资源过度占用
缺点
- 对于
DIP原则
以及OCP原则
支持不友好,功能扩展不方便
2、 Java
实现
2.1、饿汉式单例模式
饿汉式单例模式基础代码,如有功能或者业务逻辑上的需要,可以在此基础上进行扩展。
/*** <p>项目文档: TODO</p>** @author 大牧* @version V1.0*/
public class SingletonForHungry {// 1. 内部属性中直接实例化当前对象private static SingletonForHungry myInstance = new SingletonForHungry();// 2. 构造方法私有化,屏蔽外界实例化途径private SingletonForHungry () {}// 3. 提供获取实例对象的静态方法public static SingletonForHungry getInstance() {return myInstance;}}
测试代码,请独立创建一个入口类进行测试
/*** <p>项目文档: TODO</p>** @author 大牧* @version V1.0*/
public class SingletonMain {public static void main(String[] args) {// 测试代码SingletonForHungry sf = SingletonForHungry.getInstance();System.out.println(sf); // SingletonForHungry@61bbe9baSingletonForHungry sf2 = SingletonForHungry.getInstance();System.out.println(sf2); // SingletonForHungry@61bbe9ba// SingletonForHungry sf3 = new SingletonForHungry();// ERROR
// System.out.println(sf3);}
}
2.2、 懒汉式单例模式
/*** <p>项目文档: 懒汉式单例模式</p>** @author 大牧* @version V1.0*/
public class SingletonForLazy {// 1. 声明一个存放实例对象的变量private static SingletonForLazy myInstance;// 2. 构造方法私有化private SingletonForLazy() {}// 3. 提供获取当前类型实例对象的静态方法public static SingletonForLazy getInstance() {myInstance = myInstance == null ? new SingletonForLazy():myInstance;return myInstance;}
}
测试代码:
/*** <p>项目文档: TODO</p>** @author 大牧* @version V1.0*/
public class SingletonMain {public static void main(String[] args) {// 懒汉式单例 测试代码SingletonForLazy sl = SingletonForLazy.getInstance();System.out.println(sl); // SingletonForLazy@61bbe9baSingletonForLazy sl2 = SingletonForLazy.getInstance();System.out.println(sl2); // SingletonForLazy@61bbe9ba// SingletonForLazy sl3 = new SingletonForLazy();// ERROR
// System.out.println(sl3);}
}
注意:这里的单例模式,主要是业务上的限制,并不代表在代码执行过程中外界不能干预,比如通过反射的方式实例化单例类的其他实例,但是根本上来说只要符合需求的模式下,单例模式能解决我们在项目中遇到的通用问题,也就是单例模式就是一种解决方案,会因不同的场景而进行不同的设计。
3、 Python
实现
Python
本身是弱类型语言,所以单例模式的实现手段较多,我们这里简单给大家展示几种操作方式。
3.1、 单实例操作
Python
中的一切都是数据都是对象,包括类型的声明定义也是一种对象,在操作过程中根据这一特性我们可以直接构建单例模式
singleton.py
-------------------------------------------
"""
单例模式
"""
# 实现1:单实例操作
class Singleton:pass# 创建实例对象
singleton_instalce = Singleton()
# 删除类定义
del Singleton
print(singleton_instalce) # <__main__.Singleton object at 0x10c221080>singleton_instalce2 = Singleton() # NameError: name 'Singleoton' is not defined
print(singleton_instalce2)
上述代码中,通过类型Singleton
可以很方便的创建属于该类型的对象singleton_instance
,完成对象创建后删除了类型的定义,在后续的代码使用过程中,利用Python
语言本身的特性,可以通过import
方式使用该单例对象,其他Python
模块中可以按照如下方式引入使用
# 引入单例实例
from singleton import singleton_instance
3.2、 静态方法
通过类型的静态方法,提供一个获取当前类型实例化的公共API,在业务上限制该实例的单例操作模式
# 实现2:静态方法
import threading
class Singleton:_instance_lock = threading.Lock()@classmethoddef get_instance(self, *args, **kwargs):"""获取当前实例的静态方法"""if not hasattr(Singleton, "_my_instance"):# 线程锁,保证多线程访问安全with Singleton._instance_lock:Singleton._my_instance = Singleton()return Singleton._my_instancesingleton = Singleton.get_instance()
print(singleton) #<__main__.Singleton object at 0x102dc00f0>singleton2 = Singleton.get_instance()
print(singleton2) #<__main__.Singleton object at 0x102dc00f0>
但是上述的单例操作中,不排除开发人员可能会通过类型直接构建对象的行为,代码如下:
singleton3 = Singleton()
print(singleton3) #<__main__.Singleton object at 0x1012c00b8>
所以我们在这里操作的单例模式,描述为添加了业务限制的单例操作,在业务要求中如果要使用该类型的实例必须通过get_instance()
方法进行获取。
3.3、 __new__
魔法方法
Python
中的类型在实例化过程中,逐次调用了__new__(cls)
进行实例的构建和__init__(self)
进行数据的初始化操作,我们通过__new__(cls)
魔法方法直接完成单例的处理,是Python
中最常见的一种操作方式。
# 实现3:__new__()魔法方法
class Singleton:import threading_instance_lock = threading.Lock()def __init__(self, name):self.name = namedef __new__(cls, *args, **kwargs):"""构建方法"""if not hasattr(Singleton, "_instance"):with Singleton._instance_lock:Singleton._instance = object.__new__(cls)return Singleton._instance# 分别创建两个不同的实例
singleton = Singleton("tom")
singleton2 = Singleton("jerry")
# 查看两个不同实例的属性数据和内存地址
print(singleton, singleton.name) # <__main__.Singleton object at 0x101d13128> jerry
print(singleton2, singleton2.name) # <__main__.Singleton object at 0x101d13128> jerry
通过上述代码可以看到,不同时间创建的对象,最终的数据都是一致的,包括在内存中的地址,也就是表明了当前的多个实例是同一个内存中的的对象数据,因为添加了线程锁,所以该单例模式即使在多线程环境下也是安全的。
3.4、 装饰器实现
上述的几种实现方式都非常有好,尤其是通过__new__(cls)
的实现操作,但是在实际开发过程中代码的复用性并不是非常好,我们可以使用Python
中的装饰器完成单例模式的检查约束,同时也保证了代码的复用性。但是装饰器的操作模式并不是全部适用,如果一个系统中出现大量的单例对象(当然基本不可能出现),装饰器的操作模式就会特别消耗系统资源,废话不多直接看实现
# 实现4:装饰器操作
def singleton(cls):"""单例类装饰器"""# 声明一个存储对象的字典_instance = dict()def _singleton(*args, **kwargs):if cls not in _instance:_instance[cls] = cls(*args, **kwargs)return _instancereturn _singleton@singleton
class Single:def __init__(self, name):self.name = names1 = Single("tom")
s2 = Single("jerry")
print(s1) # <class '__main__.Single'>:<__main__.Single object at 0x10b3b10b8>
print(s2) # <class '__main__.Single'>:<__main__.Single object at 0x10b3b10b8>
由于Python
语言本身的灵活性,基于python
的实现方式比较多,大家可以在实现过程中自行参考。
4、 Go
实现
Go
语言是通过结构体来定义类型的,所以单例的操作就比较灵活了,这里介绍一种简单的实现操作模式
package mainimport ("fmt""sync"
)type Singleton struct {}var instance *Singleton
var once sync.Oncefunc GetInstance() *Singleton {once.Do(func() {fmt.Println("instance invoking....")instance = &Singleton{}})return instance
}
大牧絮叨设计模式:单例模式相关推荐
- 大牧絮叨设计模式:抽象工厂模式
文章目录 1. 抽象工厂模式概述 1.1. 核心组件 1.2. 优点缺点 2. `Java`实现 2.1. 工厂及产品结构的定义 2.2. 具体工厂类的实现 3. `Python`实现 4. `Go` ...
- 大牧絮叨设计模式:简单工厂模式
文章目录 1. 简单工厂模式概述 1.1.简单工厂模式核心组件 1.2.简单工厂模式优缺点 2.` Java`实现 公共父类定义 产品具体实现类 简单工厂定义 代码运行测试: 3. `Python`实 ...
- 大牧絮叨设计模式:建造者模式
文章目录 1. `建造模式` 概述 1.1. 核心组件 1.2. 优点缺陷 2. `Java` 实现 2.1. 抽象建造者`Builder` 2.2. 内聚组件`Aggregation Product ...
- 大牧絮叨设计模式:适配器模式
文章目录 1. `适配器模式`概述 1.1. 什么是适配器模式 1.2. 适配器模式的优点缺陷 2. `Java`实现 2.1. 目标类:`Power`接口 2.2. 消费类:`Alienware`类 ...
- 大牧絮叨设计模式:原型模式
文章目录 1. `原型模式`概述 1.1. 核心组件 1.2. 优点缺陷 2. `Java`实现 2.1. 原型抽象 2.2. 原型实现 2.3. 原型对象管理器 2.4. 消费者 2.5. `深.浅 ...
- 大牧絮叨设计模式:工厂方法模式
文章目录 1. 工厂方法模式概述 1.1. 工厂方法模式核心组件 1.2. 工厂方法模式优缺点 2. `Java`实现 (1) 核心工厂声明 (2) 核心产品声明 (3) 产品具体实现 (4) 工厂具 ...
- 软件设计模式“单例模式”和“工厂模式”
软件设计模式"单例模式"和"工厂模式" 单例模式 什么是单例模式 单例模式的实现方式有哪些 单例模式的优缺点 单例模式的应用场景 总结 工厂模式 什么是工厂模式 ...
- C++设计模式--单例模式详解(懒汉模式、饿汉模式、双重锁)
C++设计模式--单例模式详解(懒汉模式.饿汉模式.双重锁) 应用场景 一.单例模式是什么? 二.使用步骤 1.UML图 2.代码实现 应用场景 通常我们在做通讯的时候,我们跟服务器数据交互,假如每次 ...
- 设计模式——单例模式、工厂模式
设计模式--单例模式.工厂模式 一.六大设计原则 开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭.在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热 ...
最新文章
- 使用OClint进行iOS项目的静态代码扫描
- 王道操作系统考研笔记——2.3.3 进程互斥的硬件实现方法
- RocketMQ的组织架构和基本概念,Dledger高可用集群架构原理
- 10-2 使用Channel等待任务结束
- sql server数据库还原备份 sql语句
- Windows API-GDI入门基础知识详解(1)
- .net core部署到Ubuntu碰到的问题
- 【网络攻防】常见的网络攻防技术——黑客攻防(通俗易懂版)
- 基于mysql+php065企业公文流转系统
- FPGA中的AXI总线知识点快速学习(适合新手)
- 微信自动回复和群聊消息完善
- Python 教程之如何在 Python 中处理大型数据集CSV、Pickle、Parquet、Feather 和 HDF5 的比较
- 基于Kotlin实现学生信息管理系统【100010063】
- [零刻]EQ12EQ12Pro安装OpenWRT软路由教程
- 这些车企在企业微信里,装上高速的“组织引擎”
- Swift+Ubuntu on Mac
- 网格化管理服务系统,携同用户创新共进步
- 阿里大佬耗时3年总结Python学习清单共26章,名企Offer轻松拿到手
- springBoot项目中Graphics2D在linux上使用Font字体出现乱码或者中文字无法显示的问题
- 大年初一微信闪退?看看如何修复的 1
热门文章
- 多线程抢票_java多线程下模拟抢票
- python抢票系统代码及解说_python抢票程序
- C语言OCI的方式连接oracle数据库
- WebRTC Native M96 SDK接口封装--muteLocalAudioStream开关本地音频发送
- TVS管选型详细流程 瞬态稳压二极管
- openpyxl操作excel
- X线DR医学图像 --- DR医用滤线栅及摩尔纹详解 (二) 摩尔纹的产生机理
- 数字经济创新(Digital-economy-innovation)
- 美国高分辨率土地覆盖分类技术进展
- 智能名片迎来机遇,互联网战场从ToC向ToB转移