Welcome to kimi's blog

设计模式简介及单例模式

设计模式简介及单例模式

  1. 设计模式
    前人通过大量的验证创建出来解决一些问题的固定高效方法

  2. IT行业
    设计模式分为三大类,总共23种模式

    创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
    结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
    行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

  3. 单例模式
    类加括号无论执行多少次永远只会产生一个对象

    目的:当类中有很多非常强大的方法 在程序中很多地方都需要使用,如果不做单例,会产生很多无用的对象浪费存储空间,使用单例模式 整个程序就用一个对象

设计模式的23种方法图如下:

image

单例模块实现的多种方式

方式一:绑定给类的方法

class MyClass:
    __instance = None

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

    @classmethod
    def singleton(cls):
        if not cls.__instance:  # 判断全局的__instance是否有值
            cls.__instance = cls('kimi',18)
        return cls.__instance

# 1 单例模式下,执行多少次的类名加括号都只会产生一个对象
obj1 = MyClass.singleton()
obj2 = MyClass.singleton()
obj3 = MyClass.singleton()
print(id(obj1),id(obj2),id(obj3))  # 1467506641648 1467506641648 1467506641648

# 2.要是想产生新的对象,需要在类调用的时候传入新的数据
obj4 = MyClass('rose', 22)
obj5 = MyClass('kiki', 19)
print(id(obj4),id(obj5))  # 1582454534352 1582454534640
"""  这样的单例模式,扩展性更强一些"""

方式二:基于元类的类名加括号

class Mymeta(type):
    def __init__(self,name,bases,dict):  # 定义一个类MYsql时就触发
        # 事先从配置文件种配置来造一个Mysql的实例出来
        self.__instance = object.__new__(self)  #产生一个对象
        self.__init__(self.__instance,'kimi',18) # 给空对象初始化数据
        # 上面两步可以合成下面一步
        # self.__instance = super().__call__(*args,**kwargs)
        super().__init__(name,bases,dict)


    def __call__(self, *args, **kwargs):  # Mysql(...)时触发
        if args or kwargs:   # 判断args or kwargs 是否有值
            obj = object.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return  obj  # 传值说明我们要用新的对象
        return self.__instance  # 不传值说明我们要用单例的值


class Mysql(metaclass=Mymeta):  #不用创建对象也能触发__init__方法,因为时元类干扰了创建类的过程。 类名加括号 触发__call__方法
    def __init__(self,name,age):
        self.name = name
        self.age = age

 # 1 单例模式下,执行多少次的类名加括号都只会产生一个对象
print(Mysql.__dict__)  # {.....'_Mymeta__instance': <__main__.Mysql object at 0x00000268A06A4AF0>}
obj1 = Mysql()
obj2 = Mysql()
print(id(obj1),id(obj2))  # 1994724494064 1994724494064

 # 2.要是想产生新的对象,需要在类调用的时候传入新的数据
obj4 = Mysql('rose', 25)
obj5 = Mysql('kiki', 15)
print(id(obj4),id(obj5))   # 2000220058336 2000220058288

方式三:基于模块的单例模式

"""要是通过类的方式去调,比如func1(self),说万一要传东西,而self是绑定给对象的方法,类是不能直接调的"""
>>>把下述当作模块,通过模块点obj的形式调用
'''基于模块的单例模式:提前产生一个对象 之后导模块使用'''
class C1:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def func1(self):pass
    def func2(self):pass
    def func3(self):pass
    def func4(self):pass

obj = C1('kimi',22,'female')
# 把上述当作模块,通过模块点obj的形式调用

另一个模块去点
from django.conf  import settings

方式四:定义一个装饰器实现单例模式

def singleton(cls):  # cls = Mysql
    __instance = cls('kimi',18)
    def wrapper(*args,**kwargs):  # 判断Mysql()括号里面有没有参数
        if args or kwargs:  #
            obj = cls(*args,**kwargs)
            return obj  # 有值就会产生一个新的对象
        return __instance  # 没有值就会返回装饰器给的对象
    return wrapper

@singleton # Mysql = singleton(Mysql)
class Mysql:
    def __init__(self,name,age):
        self.name = name
        self.age = age

# 1 单例模式下,括号里面不传参数,执行多少次的类名加括号都只会产生一个对象
obj1 = Mysql()
obj2 = Mysql()
obj3 = Mysql()
print(obj3 is obj2 is obj1)  # True

# 2.要是想产生新的对象,需要在类调用的时候传入新的数据
obj4 = Mysql('kiki',20)
obj5 = Mysql('rose',18)
print(obj5 is obj4)  # False

方法五:基于元类

class MyMetaClass(type):
    def __call__(self, *args, **kwargs):
        if not self.instance:
            obj = self.__new__(self)  # 创建一个空对象
            self.__init__(obj)  # 调用__init__给对象添加独有的数据
            self.instance = obj    # 创建新的对象
        return self.instance # 返回类中定义好的intance

class C1(metaclass=MyMetaClass):
    instance = None

obj1 = C1()
obj2 = C1()
obj3 = C1()
print(id(obj1),id(obj2),id(obj3))  # 1992688159568 1992688159568 1992688159568

# 利用反射来做
posted @ 2022-11-09 17:15  魔女宅急便  阅读(31)  评论(0)    收藏  举报
Title