单例模式

Posted lulingjie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。

 

一、什么是单例模式


整个过程中只有一个实例,所有生成的实例都指向同一块内存空间,本质是为了节省空间

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p1 = Person(‘yjy‘,18)
p2 = Person(‘yjy‘,18)
print(p1)  #<__main__.Person object at 0x000002694B07E278>
print(p2)  #<__main__.Person object at 0x000002694B07E2B0>

以上p1和p2的内存空间不一样,就不是单例模式

二、实现单例模式的方法


需求:

  • 当用户输入端口和地址,实例化产生新对象
  • 当用户不输入端口和地址,每次拿到的对象,都是同一个

2.1 通过类的绑定方法

class Sql():  #定义一个Sql类
    _instance = None   #定义一个初始变量__instance=None,将第一次实例的对象传给他,有每次外面再访问就直接进行get_singleton里面的if判断
    def __init__(self,port,host):
        self.port = port
        self.host = host
    @classmethod   #运用类的绑定方法  绑定给Sql类去直接调用实例化
    def get_singleton(cls):   #cls为Sql
        # 目的是要调取Sql这个类通过从配置文件读取IP、端口参数,完成调用init方法,拿到一个实例化init方法的对象
        import settings     #导入模块
        if not cls._instance:    #如果_instance这个方法不在在类的名称空间里面
            cls._instance = cls(settings.PORT,settings.HOST)   #返回我们在settings里面设置好的端口号和主机号的内存地址
        return cls._instance   #返回这个属性的名称空间  其实就是return cls(settings.IP,settings.PORT)

#每次调用get_singleton 拿到的对象都是同一个
s1 = Sql.get_singleton()  #<__main__.Sql object at 0x000001BF2DCEECC0>
s2 = Sql.get_singleton()  #<__main__.Sql object at 0x000001BF2DCEECC0>
print(s1)
print(s2)
s3 = Sql(‘33306‘,‘192.168.1.1‘)  #重新去实例化一个东西   #Sql(ip,port)  就是调用Sql里面的init方法
print(s3)   #<__main__.Sql object at 0x000001BF2DCEECF8>
#模板
class Sql():  
    _instance = None  
    def __init__(self,port,host):
        self.port = port
        self.host = host
    @classmethod   
    def get_singleton(cls):  
        import settings     
        if not cls._instance:   
            cls._instance = cls(settings.PORT,settings.HOST)   
        return cls._instance   
s1 = Sql.get_singleton()  
s2 = Sql.get_singleton()  
print(s1)
print(s2)
s3 = Sql(‘33306‘,‘192.168.1.1‘)  
print(s3) 

2.2 通过装饰器

import settings
def get_singleton(cls):
    _instance = cls(settings.PORT,settings.HOST)  #给Sql的init方法传参,实例化得到一个对象,__instance
    def wrapper(*args,**kwargs):  #判断外面调用时是否有传值进来
        if len(args) ==0 and len(kwargs) == 0:   # 用户没有传参,
            return _instance  #直接返回默认settings的值
        return cls(*args,**kwargs)  #有用户传参,生成新对象,创建新的值,产生新的名称空间
    return wrapper

@get_singleton  #会把下面的Sql当中参数传入,相当于:Sql=get_sigoleton(Sql)
class Sql():   #Sql= singleton(Sql)   Sql = wrapper
    def __init__(self,port,host):
        self.port = port
        self.host = host

Sql = get_singleton(Sql)
s1 = Sql()
s2 = Sql()
print(s1)  #<__main__.Sql object at 0x00000188E00BE940>
print(s2)  #<__main__.Sql object at 0x00000188E00BE940>
s3 = Sql(‘3306‘,‘192.168.1.2‘)
print(s3)  #<__main__.Sql object at 0x00000188E00BECC0>
#模板
import settings
def get_singleton(cls):
    _instance = cls(settings.PORT,settings.HOST)
    def wrapper(*args,**kwargs):
        if len(args) ==0 and len(kwargs) == 0:
            return _instance
        return cls(*args,**kwargs)
    return wrapper

@get_singleton
class Sql():
    def __init__(self,port,host):
        self.port = port
        self.host = host

Sql = get_singleton(Sql)
s1 = Sql()
s2 = Sql()
print(s1)
print(s2)
s3 = Sql(‘3306‘,‘192.168.1.2‘)
print(s3)

2.3 通过元类

import settings
class Mymeta(type):
    def __init__(self,name,bases,dic):  #self是Sql类  造Sql的空对象
        self._instance = self(settings.PORT,settings.HOST)  #为空对象初始化独有的属性
    def __call__(self, *args, **kwargs):  #self是Sql类  在调用类时创建
        if len(args) == 0 and len(kwargs) == 0:  #如果没有传参
                return self._instance  #返回给空对象初始化好的属性
        obj = object.__new__(self)  #类的实例化产生一个新的对象用obj接收
        obj.__init__(*args, **kwargs)  #初始化新的obj对象
        return obj  #已经创建好的Sql对象

class Sql(metaclass=Mymeta):
    def __init__(self,port,host):
        self.port = port
        self.host = host

s1 = Sql()   #触发自定义类的__init__
s2 = Sql()
print(s1)  #<__main__.Sql object at 0x00000224460BECF8>
print(s2)  #<__main__.Sql object at 0x00000224460BECF8>
s3 = Sql(‘3306‘,‘192.168.1.2‘)
print(s3)  #<__main__.Sql object at 0x000002244D0CC6A0>
#模板
import settings
class Mymeta(type):
    def __init__(self,name,bases,dic):  #self是Sql类
        self._instance = self(settings.PORT,settings.HOST)
    def __call__(self, *args, **kwargs):  #self是Sql类
        if len(args) == 0 and len(kwargs) == 0:
                return self._instance
        obj = object.__new__(self)
        obj.__init__(*args, **kwargs)
        return obj

class Sql(metaclass=Mymeta):
    def __init__(self,port,host):
        self.port = port
        self.host = host

s1 = Sql()
s2 = Sql()
print(s1)
print(s2)
s3 = Sql(‘3306‘,‘192.168.1.2‘)
print(s3)

2.4 导入模块实现(Python的模块是天然的单例)

‘‘‘配置文件settings‘‘‘
PORT = 3306
HOST = ‘127.0.0.1‘


‘‘‘模块文件singleton‘‘‘
import settings
class Sql():
    def __init__(self,port,host):
        self.port=port
        self.host=host
s1=Sql(settings.PORT,settings.HOST)


‘‘‘执行文件‘‘‘
#方式一
def test():
    from singleton import s1
    print(s1)  #这个s1和下面的s1不是一个,但是值相同

def test2():
    from singleton import s1,Sql
    print(s1)  #这个s1和上面的s1不是一个,但是值相同
    obj = Sql(3306,‘192.168.1.1‘)  #传参的时候生成一个新的空对象
    print(obj)  #打印传进去的对象

test()   #<singleton.Sql object at 0x000001D73F0AD198>
test2()   #<singleton.Sql object at 0x000001D73F0AD198>
s3=(3308,‘192.168.1.1‘)  #<singleton.Sql object at 0x000001B0F4FEE160>


#方式二
def test():
    from singleton import s1
    print(s1)

def test2():
    from singleton import s1 as s2
    print(s2)

test()  #print(s1) <singleton.Sql object at 0x000001F578752630>
test2()  #print(s2) <singleton.Sql object at 0x000001F578752630>  #不传参s1和s2一样
from singleton import s1   #不传参就用原来定义好的对象
from singleton import Sql  
s3=Sql(3306,‘192.168.1.1‘)   #传参的时候生成新的空对象
print(s3)  #<singleton.Sql object at 0x000001F57172E128>
 

以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章

单例模式(单例设计模式)详解

Java模式设计之单例模式(二)

单例模式(饿汉式单例模式与懒汉式单例模式)

单例模式

单例模式

设计模式之单例模式