设计模式简介
设计模式是指软件设计问题的推荐方案。设计模式一般是描述如何组织代码和使用最佳实践来解决常见的设计问题。需谨记一点:设计模式是高层次的方案,并不关注具体的实现细节,比如算法和数据结构。
设计模式共分为三大类,细分为23种设计模式。
1. 创建型模式
2. 结构型模式
3. 行为型模式
单例
单例模式属于创建型模式,是一个比较常用的一个设计模式,单例模式主要作用是让一个类只有一个实例对象,因为在某些时候创建多个实例对象会浪费内存,所以目的就是为了节省内存资源。
既然是约束只能生成一个实例对象,那么就应该在实例化的过程进行修改,编写单例的方法有很多种
使用元类 __call__
代码示例(基于元类)
class Single(type): # 定义继承元类type的类
def __call__(self, *args, **kwargs): # 重写 __call__ 在类加括号调用时执行
if not hasattr(self, 'new_obj'): # 判断类名有没有指定属性
# 若没有,则添加指定属性,属性值是元类__call__的返回值也就是类名
self.new_obj = super().__call__(*args, **kwargs)
return self.new_obj
class MyClass(metaclass=Single):
def __init__(self, name):
self.name = name
obj1 = MyClass('X')
obj2 = MyClass('W')
print(obj1 is obj2)
print(obj1)
print(obj2)
打印结果
True
<__main__.MyClass object at 0x000001F9B382E350>
<__main__.MyClass object at 0x000001F9B382E350>
此时创建多个实例并不会执行,只指向一个实例。
使用 __new__ 方法
__new__
方法在类的实例化过程最先执行,默认执行 object 的__new__
方法,返回一个实例化对象,然后再调用__init__
方法,对这个对象进行初始化
代码示例
class MyCls(object): # 定义继承元类type的类
def __new__(cls, *args, **kwargs): # 重写 __new__ 方法
if not hasattr(cls, 'new_obj'): # 如果类名没有指定属性
# 给类名添加属性,属性值是 object 的__new__方法返回值
cls.new_obj = super().__new__(cls, *args, **kwargs)
return cls.new_obj # 将属性值返回
obj = MyCls()
obj1 = MyCls()
print(obj is obj1)
print(obj)
print(obj1)
打印结果
True
<__main__.MyCls object at 0x0000024968276500>
<__main__.MyCls object at 0x0000024968276500>
第一次实例化的时候,由于判断其没有指定属性,执行添加属性语句,属性值是 object 的 __new__ 方法
的返回值,最后返回指定属性的值,也就是类名,而第二次实例化的时候由于已经添加了属性,所以直接返回
object 的 __new__ 方法,所以其实他们一直是同一个属性值。
使用 @classmethod
@classmethod 会自动将类名传入到 cls 变量中
代码示例
class MyCls(object):
_instance = None # 定义一个变量用于判断
def __init__(self):
pass
@classmethod # 定义一个类方法
def singleton(cls):
if not cls._instance: # 如果类中的指定属性为None
cls._instance = MyCls() # 设置属性,属性值为实例对象
return cls._instance # 将指定属性返回
obj1 = MyCls.singleton() # 只能用类方法来获取实例对象
obj2 = MyCls.singleton() # 只能用类方法来获取实例对象
print(obj1)
print(obj2)
打印结果
<__main__.MyCls object at 0x000002396ABB5D20>
<__main__.MyCls object at 0x000002396ABB5D20>
这个有些不同,只能用类方法来获取实例对象。第一次调用类方法创建实例对象的时候在类方法中得到了一个
实例对象返回值,而在第二次调用类方法创建对象的时候已经有了指定属性,不满足类方法中的判断条件,所
以获得的还是第一次实例化得到的对象。
使用装饰器
使用装饰器实现实例化并返回出来
代码示例
def outer(cls): # 定义装饰器
_instance = None # 定义变量用于判断
def inner(*args, **kwargs):
nonlocal _instance # 声明变量
if not _instance: # 如果变量是 None
_instance = cls(*args, **kwargs) # 设置属性,属性值为实例对象
return _instance
return inner
@outer # 调用装饰器,将类名传入到cls,也就是此时相当于 outer(MyCls)
class MyCls:
pass
obj = MyCls()
obj1 = MyCls()
print(obj)
print(obj1)
打印结果
<__main__.MyCls object at 0x00000165FDE05D20>
<__main__.MyCls object at 0x00000165FDE05D20>
使用模块
模块的方式就是在一个py文件中定义一个类,并实例化一个对象,之后在其他文件导入这一对象