单利模式的四种方式

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

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

单利模式相关内容

内容

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

角色

单利

使用场景

当类只有一个实例而且客户可以从一个众所周知的访问点访问它时
比如:数据库链接、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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • LeetCode77:Combinations[通俗易懂]

    LeetCode77:Combinations

    2022年1月24日
    49
  • java integer long 转换_long(Long)与int(Integer)之间的转换

    java integer long 转换_long(Long)与int(Integer)之间的转换1.将long型转化为int型,这里的long型是基础类型:longa=10;intb=(int)a;2.将Long型转换为int型的,这里的Long型是包装类型:Longa=10;intb=a.intValue();3.将Long型转换为Integer型的,这里的Long型是包装类型:Longa=10;;Integerb=a.intValue(…

    2022年6月5日
    43
  • lorawan与lora的区别_交换机wan口和lan口的区别

    lorawan与lora的区别_交换机wan口和lan口的区别LoRaWAN与LoRa的区别在物联网技术快速发展的今天,NB-IoT、LoRa、SigFox等技术名词经常进入我们的视野中,对于刚刚接触物联网领域的人来说,在一大堆名词面前可能会混淆。面对类似于LoRa和LoRaWAN这样容易混淆的名词,其实只要系统梳理一下就可以发现其中的区别。今天我们就来看看LoRaWAN与LoRa两者的区别:……

    2022年10月19日
    2
  • 圆桌排列组合问题_圆桌相邻概率

    圆桌排列组合问题_圆桌相邻概率假设有来自 m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为 ri(i=1,2,…,m)。会议餐厅共有 n 张餐桌,每张餐桌可容纳 ci(i=1,2,…,n) 个代表就餐。为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法,给出满足要求的代表就餐方案。输入格式第 1 行有 2 个正整数 m 和 n,m 表示单位数,n 表示餐桌数。第 2 行有 m 个正整数,分别表示每个单位的代表数 ri。第 3 行有 n 个正整数,分别表示每个餐桌的容量 ci。输

    2022年8月9日
    9
  • VSCode汉化_vscode汉化插件

    VSCode汉化_vscode汉化插件1.打开VSCode点击箭头指示地方在搜索框中输入chinese然后安装中文简体2.按住Ctrl+shift+p选择配置显示语言然后会看见下面的样子添加"locale&qu

    2022年8月2日
    7
  • onResume的作用

    onResume的作用描述:今天在做一个功能的时候,从Aactivity跳到Bactivity。由于Bactivity的操作,影响了Aactivity的数据,所以再回到A的时候,需要A能够进行刷新操作。但是默认跳回去的时候,A界面还是上次那个。解决方案:重写Aactivity的onResume()方法,在onResume()方面里进行刷新操作。因为按照activity的生命周期模型,当activ

    2022年6月2日
    65

发表回复

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

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