单列模式

单列模式

一、单列模式

1.1 什么是单列模式

  1. 整个过程中只是一个实例,所有生成的实例都指向同一块内存地址
  2. 基于某种方法实例化多次得到的实例是同一个

理解:

就像a= 1``b=1``c =1对a、b、c的地址进行打印,都是相同的

1.2 为啥用单列模式

当实例化多次得到的对象中存放的属性都一样的情况,应该多个对象指向同一个内存,即同一个实例。

二、实现单列模式

模块settings

#settings.py
PORT=3306
HOST='127.0.0.1'

方法1(通过类的绑定方法)

要求:

  1. 当用户输入端口和地址,实例化产生新对象
  2. 当用户不输入端口和地址,每次拿到的对象,都是同一个
class Sql():
    _instance = None

    def __init__(self, port, host):
        self.port = port
        self.host = host

    @classmethod
    def get_sigoleton(cls):
        import settings
        if cls._instance:
            return cls._instance
        else:
            cls._instance = cls(settings.PORT, settings.HOST)
            return cls._instance


s1 = Sql.get_sigoleton()
s2 = Sql.get_sigoleton()
s3 = Sql.get_sigoleton()
print(s1)  # <__main__.Sql object at 0x000001D7F1BE1188>

print(s2)  # <__main__.Sql object at 0x000001D7F1BE1188>

print(s3)  # <__main__.Sql object at 0x000001D7F1BE1188>
s4 = Sql('33306', '192.168.1.1')
print(s4)  # <__main__.Sql object at 0x000001B2AD820348>

法二、通过装饰器

要求:

  1. 当用户输入端口和地址,实例化产生新对象
  2. 当用户不输入端口和地址,每次拿到的对象,都是同一个
def get_sigoleton(cls):
    # cls就是装饰的时候把Sql传入
    _instance = None

    def wrapper(*args, **kwargs):
        if len(args) != 0 or len(kwargs) != 0:
            # 表示传入参数生成新对象
            res = cls(*args, **kwargs)
            return res
        else:
            import settings
            nonlocal _instance
            if not _instance:
                _instance = cls(settings.PORT, settings.HOST)
            return _instance

    return wrapper


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


s1 = Sql()
s2 = Sql()
s3 = Sql()
print(s1)  # <__main__.Sql object at 0x000001E7AED841C8>

print(s2)  # <__main__.Sql object at 0x000001E7AED841C8>

print(s3)  # <__main__.Sql object at 0x000001E7AED841C8>

法三、通过元类

要求:

  1. 当用户输入端口和地址,实例化产生新对象
  2. 当用户不输入端口和地址,每次拿到的对象,都是同一个
class Mymeta(type):
    def __init__(self, name, bases, dic):
        import settings
        # 把实例化好的对象,放到类的名称空间内
        self._instance = self(settings.PORT, settings.HOST)
    def __call__(self, *args, **kwargs):
        # self是谁?是Sql类
        if len(args) != 0 or len(kwargs) != 0:
            obj = object.__new__(self)
            obj.__init__(*args, **kwargs)
            return obj
        else:
            return self._instance

class Sql(metaclass=Mymeta):
    # 相当于Sql = Mymeta(name,bases,dic)
    # 这个会调用Mymeta的__init__
    # 在里面已经向类的名称空间放了一个对象
    def __init__(self, port, host):
        self.port = port
        self.host = host
print(Sql.__dict__)
s1 = Sql()

法四、通过通过模块导入(python的模块是天然的单例)

要求:

  1. 当用户输入端口和地址,实例化产生新对象
  2. 当用户不输入端口和地址,每次拿到的对象,都是同一个
#sigonleton.py
import settings
class Sql():
    def __init__(self,port,host):
        self.port = port
        self.host = host
s1 = Sql(settings.PORT,settings.HOST)
        
def test():
    from sigonleton import s1
    print(s1.port)
    print(s1)
def teat2():
    from sigonleton import s1 as s2
    print(s2)
test()
teat2()
原文地址:https://www.cnblogs.com/SkyOceanchen/p/11461630.html