单例模式总结-Python实现
面试里每次问设计模式,必问单例模式
来自《Python设计模式》(第2版)
1.理解单例模式:
确保类有且只有一个特定类型的对象,提供全局访问点,控制共享资源的并行访问
使用情景:日志打印、数据库操作、打印机后台处理、配置文件
原则:避免对统一资源产生相互冲突的请求
python中的None是单例模式实现的
2.实现方法
使构造函数自由化,并创建一个静态方法来完成对象的初始化
Python中无法创建私有的构造函数
于是可以通过覆盖new这个特殊方法来控制对象的创建,改写为创建之前先检查是否存在
实现一个单例模式吧:
class Singleton(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
3.单例模式的饿汉式和懒汉式
饿汉式:饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了。
懒汉式:节约资源在有需要的时候再创建对象,使对象的创建发生在调用,python中可以用@classmethod装饰器来修饰,定义类的方法 ,还是通过类变量来保存对象和判断
(@classmethod装饰器她定义操作类的方法,他的第一个参数不是self,而是cls,是类本身而不是实例,最常见的用途就是定义备选的构造方法)
两者比较
1、线程安全:
饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题
懒汉式本身是非线程安全的,为了实现线程安全需要改写,比如给创建线程的类方法加锁,getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成instance 被多次实例化。
利用python的装饰器实现类似java中的synchronized
2、资源加载和性能:
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会++占据一定的内存++,但是相应的,在++第一次调用时速度也会更快++,因为其资源已经初始化完成。
而懒汉式顾名思义,++会延迟加载++,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。
3.单态模式
让所有实例共享相同的状态,更关注状态和行为,而不是同一性
python中使用dict这个特殊方法存储一个类所有对象的状态,原本他是存储对象的状态的,作为类的状态就可以随不同对象更新状态(所谓状态就是,显式的变量和方法)
4.单例模式应用场景
1.数据库
数据库类应用为单例,操作就不会有冲突,也可以节约资源
比如数据库连接池的实现
2.运行状态监控服务
维护监控服务器列表,添加或者删除由同一个对象来完成
3.Windows的文件管理器
避免多线程多进程对同一个文件进行操作
5.什么情况下不能用单例模式?
多线程没办法直接用单例模式,加了锁同步了才能用
# coding:utf-8
import threading
def synchronized(func):
func.__lock__ = threading.Lock()
def lock_func(*args, **kwargs):
with func.__lock__:
return func(*args, **kwargs)
return lock_func
class Singleton(object):
"""
单例模式
"""
instance = None
@synchronized
def __new__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = object.__new__(cls, *args, **kwargs)
return cls.instance
单例模式简单易用,但是也是所有设计模式中最容易滥用的模式。当你的类想得到很好的扩展时,不能使用单例模式。
单例模式缺点
1.扩展困难,由于GetInstance静态函数没有办法生成子类的实例
2.隐式使用引起类结构不清晰,依赖关系很难发现
3.导致程序内存泄露的问题。只是调用了GetInstance生成唯一的实例,却永远new被封装在GetInstance里忘了去释放内存
网友评论