设计模式、单例模式及其多种实现方式
目录
一、设计模式
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