单利模式的四种方式

单利模式相关内容内容角色使用场景优点与单利模式功能相似的概念:全局变量、静态变量(方法)试问?为什么用单例模式,不用全局变量呢?答、全局变量可能会有名称空间的干扰,如果有重名的可能会被覆

大家好,又见面了,我是你们的朋友全栈君。

单利模式相关内容

内容

保证一个类只有一个实例,并提供一个访问它的全局访问点

角色

单利

使用场景

当类只有一个实例而且客户可以从一个众所周知的访问点访问它时
比如:数据库链接、Socket创建链接

优点

对唯一实例的受控访问
单利相当于全局变量,但防止了命名空间被污染

与单利模式功能相似的概念:全局变量、静态变量(方法)

  试问?为什么用单例模式,不用全局变量呢?

  答、全局变量可能会有名称空间的干扰,如果有重名的可能会被覆盖

单例模式的实现方式

1、文件导入的形式(常用)

s1.py

class Foo(object):
    def test(self):
        print("123")

v = Foo()
#v是Foo的实例
s2.py from s1 import v as v1 print(v1,id(v1)) #<s1.Foo object at 0x0000000002221710> 35788560 from s1 import v as v2 print(v1,id(v2)) #<s1.Foo object at 0x0000000002221710> 35788560 # 两个的内存地址是一样的 # 文件加载的时候,第一次导入后,再次导入时不会再重新加载。

2、基于类实现的单例模式

# ======================单例模式:无法支持多线程情况===============

class Singleton(object):

    def __init__(self):
        import time
        time.sleep(1)

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance

import threading

def task(arg):
    obj = Singleton.instance()
    print(obj)

for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()


# ====================单例模式:支持多线程情况================、

import time
import threading
class Singleton(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        time.sleep(1)

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:   #为了保证线程安全在内部加锁
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance


def task(arg):
    obj = Singleton.instance()
    print(obj)
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)

# 使用先说明,以后用单例模式,obj = Singleton.instance()
# 示例:
# obj1 = Singleton.instance()
# obj2 = Singleton.instance()
# print(obj1,obj2)
# 错误示例
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)

3、基于__new__实现的单例模式(最常用)

# =============单线程下执行===============
import threading
class Singleton(object):

    _instance_lock = threading.Lock()
    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    # 类加括号就回去执行__new__方法,__new__方法会创建一个类实例:Singleton()
                    Singleton._instance = object.__new__(cls)  # 继承object类的__new__方法,类去调用方法,说明是函数,要手动传cls
        return Singleton._instance  #obj1
        #类加括号就会先去执行__new__方法,在执行__init__方法
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)

# ===========多线程执行单利============
def task(arg):
    obj = Singleton()
    print(obj)

for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()

# 使用先说明,以后用单例模式,obj = Singleton()
# 示例
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)

4、基于metaclass(元类)实现的单例模式

"""
1.对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法
2.类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)

# 第0步: 执行type的 __init__ 方法【类是type的对象】
class Foo:
    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        pass

# 第1步: 执行type的 __call__ 方法
#        1.1  调用 Foo类(是type的对象)的 __new__方法,用于创建对象。
#        1.2  调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。
obj = Foo()
# 第2步:执行Foo的 __call__ 方法
obj()
"""

# ===========类的执行流程================
class SingletonType(type):
    def __init__(self,*args,**kwargs):
        print(self)  #会不会打印?  #<class '__main__.Foo'>
        super(SingletonType,self).__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs):  #cls = Foo
        obj = cls.__new__(cls, *args, **kwargs)
        obj.__init__(*args, **kwargs)
        return obj


class Foo(metaclass=SingletonType):
    def __init__(self,name):
        self.name = name
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls, *args, **kwargs)
'''
    1、对象是类创建的,创建对象时类的__init__方法会自动执行,对象()执行类的__call__方法
    2、类是type创建的,创建类时候type类的__init__方法会自动执行,类()会先执行type的__call__方法(调用类的__new__,__init__方法)
    Foo 这个类是由SingletonType这个类创建的
'''
obj = Foo("hiayan")


# ============第三种方式实现单例模式=================
import threading

class SingletonType(type):
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

class Foo(metaclass=SingletonType):
    def __init__(self,name):
        self.name = name


obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)

单例模式的应用

(会在数据库连接池中用到单例模式),详见以下示例操作

pool.py

import pymysql
import threading
from DBUtils.PooledDB import PooledDB

class SingletonDBPool(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        self.pool = PooledDB(
            creator=pymysql,  # 使用链接数据库的模块
            maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
            mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建

            maxcached=5,  # 链接池中最多闲置的链接,0和None不限制
            maxshared=3,
            # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
            blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
            maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
            setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
            ping=0,
            # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123',
            database='pooldb',
            charset='utf8'
        )

    def __new__(cls, *args, **kwargs):
        if not hasattr(SingletonDBPool, "_instance"):
            with SingletonDBPool._instance_lock:
                if not hasattr(SingletonDBPool, "_instance"):
                    SingletonDBPool._instance = object.__new__(cls, *args, **kwargs)
        return SingletonDBPool._instance

    def connect(self):
        return self.pool.connection()

app.py

from pool import SingletonDBPool

def run():
    pool = SingletonDBPool()
    conn = pool.connect()
    # xxxxxx
    cursor = conn.cursor()
    cursor.execute("select * from td where id=%s", [5, ])
    result = cursor.fetchall()  # 获取数据
    cursor.close()
    conn.close()

if __name__ == '__main__':
    run()

 用装饰器实现的单利模式

#
def wrapper(cls):
    instance = {}
    def inner(*args,**kwargs):
        if cls not in  instance:
            instance[cls] = cls(*args,**kwargs)
        return instance[cls]
    return inner

@wrapper
class Singleton(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

obj1 = Singleton('haiyan',22)
obj2 = Singleton('xx',22)
print(obj1)
print(obj2)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/124468.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • tomcat安装配置详解_tomcat下载安装及配置教程

    tomcat安装配置详解_tomcat下载安装及配置教程tomcat保姆级安装教程Tomcat安装教程(以tomcat-9.0.62为例:)1.下载安装包可以从官网下载安装包:(1)从官网下载输入网址进入官网sshttp://tomcat.apache.org/

    2022年9月19日
    3
  • plsqldev 日期格式

    plsqldev 日期格式之前装win7+oracle11R2(64)+ instantclient_11_2(32)+PLSQL(32)费了很大力气,见前一个帖子,后果就是plsql启动时读的环境变量位置是五花八门,可能是注册表中oraclehone下的,也可能是instantclient下的或者是电脑高级属性中环境变量,当然start.bat中的设置优先。  plsql中执行以下语…

    2022年5月10日
    81
  • mysql 慢查询日志分析[通俗易懂]

    mysql 慢查询日志分析[通俗易懂]1.查找mysqlmy.ini文件C:\ProgramData\MySQL\MySQLServer5.72.查看mysql慢查询日志位置showvariableslike’%slow_query_log%’;3.查看mysql慢查询时间showvariableslike’long_query_time’;4.修改mysql修改慢查询时间找到my.ini文件修改long_query_time设置值,重启服务mysql…

    2022年10月11日
    3
  • 怎么新建pytest的ini文件_qt读写配置文件

    怎么新建pytest的ini文件_qt读写配置文件前言pytest配置文件可以改变pytest的运行方式,它是一个固定的文件pytest.ini文件,读取配置信息,按指定的方式去运行查看pytest.ini的配置选项pytest-h找到以下

    2022年7月28日
    16
  • django mysqlclient_MySQL无法安装

    django mysqlclient_MySQL无法安装mac系统安装mysqlclient时,会报错OSError:mysql_confignotfound解决办法在项目路径下输入以下内容PATH="$PATH":/usr

    2022年7月31日
    4
  • 视频文件无效怎么修复_google chrome怎么设置兼容模式

    视频文件无效怎么修复_google chrome怎么设置兼容模式发现问题以Ubuntu系统为例,我们通过genpac生成autoproxy.pac文件,然后点击系统设置->网络->代理设置->自动,在输入框中输入file://绝对路径/autoproxy.pac。设置好以后,Chrome应当可以自动切换网络,但是Chrome无法访问google的搜索引擎,而火狐浏览器可以正常访问。分析问题出现上面问题的唯一可能就是Chrome设置有误,…

    2022年10月18日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号