设计模式: 单例模式

什么是设计模式?我也不知道,我认为设计模式就是编程时,为了提高代码复用率、可扩展性、稳定性等特点而编写的代码架构设计方法, 设计模式是用来提升代码的健壮行、可扩展性、代码复用率等特点的手段。其实我也是瞎bb,等我真的理解了,一定过来纠正这段话。

单例模式:一个类只能创建一个实例,所有调用这个类的对象都共享相同实例的设计方法被称为单例模式。

目录

  • 单例模式的优点、适用场景
  • 单例模式的python实现
  • 单例模式的不同变种
  • 单例模式需要关注的问题

单例模式的优点、适用场景

优点: 单例模式只创建一个类的实例,减少了不同实例占用的内存空间和创建实例花费的时间
使用场景: 单例模式适用于只需要一个实例的场景, 如: 线程池、缓存实例、注册表操作对象、数据库操作对象、日志操作对象等,这些场景的共同点是如果有多个对象,不同对象对共享的数据进行操作时可能造成读写数据不同步, 导致数据不正确
总结:单例模式适用于在不同位置需要对同一个共享对象操作的场景

单例模式的python实现

python可通过__new__方法、装饰器、元类、分割模块四种方式来实现, 其中分割模块的方式此处不记载

方式一:new方法

1
2
3
4
5
6
class Singleton(object):
def __new__(cls):
print(cls)
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance

方式二: 装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def Singleton(cls):
_instance = {}
def _singleton(*args, **argv):
if cls not in _instance:
_instance[cls] = cls(*args, **argv)
return _instance[cls]
return _singleton

@Singleton
class db(object):
def __init__(self, dbname):
self.dbname = dbname
def conn(self):
print(self.dbname)

d1 = db("idsweb")
d1.conn()
print('the address is: 'd1)
d2 = db("ipsweb")
d2.conn()
print('the address is: ', d2)

方式三: 元类
python中所有的数据类型都有一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class SingletonType(type):

def __init__(self,*args,**kwargs):
print("enter SingletonType.__init__")
super(SingletonType,self).__init__(*args,**kwargs)

def __call__(cls, *args, **kwargs): # 这里的cls,即Foo类
print("enter SingletonType.__call__")
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType, cls).__call__(*args, **kwargs)
return cls._instance

'''
python创建类时, 特殊函数的调用顺序: __new__、__init__、__call__
'''
class Foo(metaclass=SingletonType):
def __init__(self, name):
print("enter Foo.__init__")
self.name = name
print(self.name)
def __new__(cls, *args, **kwargs):
print("enter Foo.__new__")
return object.__new__(cls)

obj = Foo('xx')
print(obj)
# 当创建过类foo的实例后, 再次调用Foo函数创建类实例时, 将不会调用Foo类的__new__()和__init__()
obj1 = Foo("x1x")
print(obj1)

单例模式的不同变种

  • 懒汉模式
  • 饿汉模式

懒汉模式

概念:当类被第一次被调用时, 创建该类的一个实例;以后调用类的时候, 直接返回类的实例
问题:根据对单例模式的理解, 不管是懒汉模式还是饿汉模式最终创建的对象的内存应该是同一块内存地址, 但是根据书上、网上给出的代码实测之后发现并不是如此, 因此这里保留疑问, 先不总结

饿汉模式

概念:当类被调用时, 不创建类的实例, 类有一个getInstance方法, 当调用该方法时, 将创建类的实例
问题:与懒汉模式相同, 均无证实, 因此先保留

单例模式需要关注的问题

  • 线程安全问题

线程安全问题主要存在于懒汉模式中, 当多个线程同时调用实例时, 将可能出现同时调用getInstance的现象

owefsad wechat
进击的DevSecOps,持续分享SAST/IAST/RASP的技术原理及甲方落地实践。如果你对 SAST、IAST、RASP方向感兴趣,可以扫描下方二维码关注公众号,获得更及时的内容推送。
0%