设计模式、单例模式及其多种实现方式

一、设计模式

1.设计模式简介

​ 前人通过大量的验证,所创建出来的解决一些问题的固定高效方法

2.IT行业的设计模式

IT行业的设计模式一共有23种,分为:创建型、结构型、行为型

  • 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

  • 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

二、单例模式及其多种实现方式

定义确保一个类最多只有一个实例,并提供一个全局访问点

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

类中的方法,类的对象来调用是最方便的

单例模式实现的多种方式:

1.运用装饰器@classmethod实现单例模式

class C1:
    __instance = None

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

    @classmethod
    def singleton(cls):
        if not cls.__instance:
            cls.__instance = cls('duoduo', [])
        return cls.__instance


obj1 = C1.singleton()
obj2 = C1.singleton()
obj3 = C1.singleton()
print(id(obj1), id(obj2), id(obj3))  # 4306218672 4306218672 4306218672

2.基于元类生成的单例

通过定义一个继承type的类MyMeta,我们可以派生__init__方法,从而可以定制一个类的行为,当我们不传参的时候,会默认为单例模式传参时则会正常产生其他实例

class MyMeta(type):
    def __init__(cls, name, bases, dic):  # 定义类MyMeta时就触发
        # 事先先从配置文件中取配置来造一个Mysql的实例出来
        cls.__instance = object.__new__(cls)  # 产生对象
        cls.__init__(cls.__instance, 'jason', 18)  # 初始化对象
        # 上述两步可以合成下面一步
        # self.__instance=super().__call__(*args,**kwargs)
        super().__init__(name, bases, dic)

    def __call__(cls, *args, **kwargs):  # MyMeta(...)时触发
        if args or kwargs:  # args或kwargs内有值
            obj = object.__new__(cls)
            cls.__init__(obj, *args, **kwargs)
            return obj
        return cls.__instance


class Mysql(metaclass=MyMeta):
    def __init__(self, name, age):
        self.name = name
        self.age = age


obj1 = Mysql()
obj2 = Mysql()  # obj1 和 obj2都是同一个实例
print(obj1.name)
print(obj2.name)
print(id(obj1), id(obj2))  # 4302991264 4302991264
obj3 = Mysql('tony', 321)  # 当传进去不同的参数时,也可以产生其他对象
obj4 = Mysql('kevin', 222)
print(id(obj3), id(obj4))  # 4302990736 4302990544

3.基于模块的单例模式

基于模块的单例模式:提前产生一个对象,之后导模块使用

class C1:
    def __init__(self, name):
        self.name = name

obj = C1('jason')

"""在run1.py、run2.py文件中,去导入该obj,
由于导入模块只发生一次,那么在该文件中
那么这些对象的id()是一样的
"""

4.基于装饰器的单例模式

def outer(cls):
    # 该对象在类Mysql被装饰上outer的时候就已经实例化完毕
    _instance = cls('jason', 18)
    def inner(*args, **kwargs):
        # 判断是否传入参数,传入参数表示要实例化新的,不传表示用默认的
        if args or kwargs:
            obj = cls(*args, **kwargs)
            return obj
        return _instance

    return inner


@outer  # Mysql=outer(Mysql)
class Mysql:
    def __init__(self, host, port):
        self.host = host
        self.port = port

# 这样可以实现单例
obj1 = Mysql()
obj2 = Mysql()
obj3 = Mysql()
print(obj1 is obj2 is obj3)  # True
# 也可以传入其他参数
obj4 = Mysql('1.1.1.3', 3307)
obj5 = Mysql('1.1.1.4', 3308)
print(obj3 is obj4)  # False

5.基于__new__ 的单例模式

class Mysql(object):
    _instance = None
    def __init__(self,name):
        self.name = name

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)
        return cls._instance

obj = Mysql('egon')
obj1 = Mysql('jason')
print(id(obj),id(obj1))

6.基于字典

def singleton(cls):
    # 创建一个字典用来保存类的示例对象
    instance = {}
    def inner(*args, **kwargs):
        # 先判断这个类有没有对象
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)
        return instance[cls]
    return inner
posted @ 2022-11-09 16:41  Duosg  阅读(79)  评论(0编辑  收藏  举报