目录
问题:通过装饰器实现单例模式,只要任意一个类使用该装饰器装饰,那么就会变成一个单例模式的类。意味着这个装饰器是通用的。
#单例模式装饰器
def single(func):
instance={}
def fun(*args,**kwargs):
if func in instance:
return instance[func]
else:
instance[func]=func(*args,**kwargs)
return instance[func]
return fun
# Test=single(Test)
@single#这里有一个类,作为装饰器去装饰一下,就变成一个单例模式。
class Test:
pass
@single#这个类用装饰器装饰一下,也变成一个单例模式。
class MyTest:
pass
#下面如果还有其它类,同样可以通过这个装饰器去装饰。只要被装饰了,那么它就会变成一个单例模式。
class Decorator:
pass
通过装饰器来实现单例模式的话,就要想下,当我们调用这个Test类创建对象的时候,直接调用类创建对象。实际上是调用类里面的new方法去创建的。
创建对象的时候,如果使用@single装饰器装饰了这个类,装饰器装饰了这个类的时候相当于执行了这样的一个代码:Test=single(Test)
把Test类传进去。
这个类被装饰器装饰完了之后,实际上这个Test已经不再是个类了。Test指向的是外层装饰器,返回的是内层装饰器的一个函数。
接下来,创建对象,它实际并没有创建对象,它实际上是调用了fun()函数。
对象只能是在装饰器内部来创建,要控制创建对象的次数的话,可以在这个里面实现:
#单例模式装饰器
def single(func):
instance={}
def fun(*args,**kwargs):
if func in instance:
return instance[func]
else:
instance[func]=func(*args,**kwargs)
return instance[func]
return fun
# Test=single(Test)
@single#这里有一个类,作为装饰器去装饰一下,就变成一个单例模式。
class Test:
pass#在这里重写new方法再去实现,已经没有什么意义了。因为创建t1=Test()对象的时候,
#不是触发里面这个方法的。直接调用这个Test类去创建对象的。
t1=Test()#它实际并没有创建对象,它实际上是调用了fun()函数。
@single#这个类用装饰器装饰一下,也变成一个单例模式。
class MyTest:
pass
#下面还有其它类,同样可以通过这个装饰器去装饰。只要被装饰了,那么它就会变成一个单例模式。
class Decorator:
pass
控制这个Test()调用,可以控制对象的创建次数。
在这个fun()函数里面怎么控制呢?首先在装饰器里面定义一个变量:
instance={}
Test()
调用这个类创建对象的时候,实际上是调用了fun()这个函数。
调用fun()这个函数的时候,看到里面做的事情:
下面这个func是上面这个func传过来的,实际上就是这个Test类:
#单例模式装饰器
def single(func):
instance={}
def fun(*args,**kwargs):
if func in instance:
return instance[func]
else:
instance[func]=func(*args,**kwargs)
return instance[func]
return fun
# Test=single(Test)
@single#这里有一个类,作为装饰器去装饰一下,就变成一个单例模式。
class Test:
pass#在这里重写new方法再去实现,已经没有什么意义了。因为创建t1=Test()对象的时候,
#不是触发里面这个方法的。直接调用这个Test类去创建对象的。
t1=Test()#它实际并没有创建对象,它实际上是调用了fun()函数。
@single#这个类用装饰器装饰一下,也变成一个单例模式。
class MyTest:
pass
#下面还有其它类,同样可以通过这个装饰器去装饰。只要被装饰了,那么它就会变成一个单例模式。
class Decorator:
pass
为了更好理解一些,修改了下代码,把func改成了cls:
#单例模式装饰器
def single(cls):
instance={}
def fun(*args,**kwargs):
if cls in instance:
return instance[cls]
else:
instance[cls]=cls(*args,**kwargs)
return instance[cls]
return fun
# Test=single(Test)
@single#这里有一个类,作为装饰器去装饰一下,就变成一个单例模式。
class Test:
pass#在这里重写new方法再去实现,已经没有什么意义了。因为创建t1=Test()对象的时候,
#不是触发里面这个方法的。直接调用这个Test类去创建对象的。
t1=Test()#它实际并没有创建对象,它实际上是调用了fun()函数。
@single#这个类用装饰器装饰一下,也变成一个单例模式。
class MyTest:
pass
#下面还有其它类,同样可以通过这个装饰器去装饰。只要被装饰了,那么它就会变成一个单例模式。
class Decorator:
pass
判断这个Test类在不在创建的字典里面:
为什么要做这个判断呢?
如果这个Test类不在创建的空字典里面,通过这个类去创建一个实例对象:
类作为键,对象作为值。然后把它添加到这个字典里面:
如果这个Test类在创建的字典里面,就说明之前通过这个类已经创建过对象,已经把它保存进去了。直接返回这个对象:
通过这样的方式就能实现一个单例模式。
这个地方不推荐用列表,原因:用来装饰一个类,通过这个类创建一个对象。通过append添加到列表里面,这个类创建的对象在列表的第一个位置,在下标为0的位置。
再装饰一个类,第二个对象在下标为1的位置。
装饰一个类,没有任何问题,装饰2个类或以上,返回的时候到底是返回第一个对象还是返回第二个对象还是返回第三个对象呢?所以用列表是不行的。
字典和列表的用法,要区分清楚。单例模式和装饰器是面试必问的题目。熟能生巧,代码需要多加练习。
清菡和你们一样,也收藏资料,2T的网盘塞满了,但是过去了这么多年,也没看过。学习的效率比较低,学的比较少。所以就要以终为始,要事第一!优先更新自己觉得比较重要的技术栈,抛弃无效社交。天下大事必作于细!欢迎指点文章不足之处,谢谢!
除标明“图片来自网络”的图片,其它文章中的图片皆为本人所画,计算机知识都一样,如有雷同,纯属巧合。