聊聊 Python 面试最常被问到的几种设计模式(上)
1. 前言
在很多人的印象里,Python 作为一款动态编程语言,在日常开发中也很少涉及到设计模式
事实上,任何一个编程语言都可以使用设计模式,它可以保证代码的规范性,只是每一种语言的实现方式略有不同而已
今天我们聊聊 Python 面试中,常被问到的 5 种设计模式,它们是:单例模式、工厂模式、构建者模式、代理模式、观察者模式
2. 单例模式
单例模式,是最简单常用的设计模式,主要目的是保证某一个实例对象只会存在一个,减少资源的消耗
Python 单例模式有很多实现方式,这里推荐下面 2 种
第 1 种,重写 __new__ 方法
定义一个实例变量,在 __new__ 方法中保证这个变量仅仅初始化一次
# 单例模式
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
使用方式如下:
if __name__ == '__main__':
# 构建3个实例
instance1 = Singleton()
instance2 = Singleton()
instance3 = Singleton()
# 打印出实例的内存地址,判断是否是同一个实例
print(id(instance1))
print(id(instance2))
print(id(instance3))
第 2 种,闭包定义装饰器
使用闭包的方式定义一个单例装饰器,将类的定义隐藏到闭包函数中
def singleton(cls):
"""
定义单例的装饰器(闭包)
:param cls:
:return:
"""
_instance = {}
def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return _singleton
使用上面装饰器的类,构建的实例都能保证单例存在
@singleton
class Singleton(object):
"""单例实例"""
def __init__(self, arg1):
self.arg1 = arg1
使用方式如下:
if __name__ == '__main__':
instance1 = Singleton("xag")
instance2 = Singleton("xingag")
print(id(instance1))
print(id(instance2))
需要注意的是,上面 2 种方式创建的单例并不适用于多线程
要保证多线程中构建的实例对象为单例,需要在 __new__ 函数中使用 threading.Lock() 加入同步锁
class Singleton(object):
"""
实例化一个对象
"""
# 锁
_instance_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = object.__new__(cls)
return Singleton._instance
使用的时候,在线程任务中实例化对象,运行线程即可
def task(arg):
"""
任务
:param arg:
:return:
"""
instance = Singleton()
print(id(instance), '\n')
if __name__ == '__main__':
# 3个线程
for i in range(3):
t = threading.Thread(target=task, args=[i, ])
t.start()
这样,就保证了多线程创建的实例是单例存在的,不会导致脏数据!
3. 工厂模式
# 定义一系列水果
class Apple(object):
"""苹果"""
def __repr__(self):
return "苹果"
class Banana(object):
"""香蕉"""
def __repr__(self):
return "香蕉"
class Orange(object):
"""橘子"""
def __repr__(self):
return "橘子"
class FactorySimple(object):
"""简单工厂模式"""
@staticmethod
def get_fruit(fruit_name):
if 'a' == fruit_name:
return Apple()
elif 'b' == fruit_name:
return Banana()
elif 'o' == fruit_name:
return Orange()
else:
return '没有这种水果'
if __name__ == '__main__':
# 分别获取3种水果
# 输入参数,通过简单工厂,返回对应的实例
instance_apple = FactorySimple.get_fruit('a')
instance_banana = FactorySimple.get_fruit('b')
instance_orange = FactorySimple.get_fruit('o')
import abc
from factory.fruit import *
class AbstractFactory(object):
"""抽象工厂"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def get_fruit(self):
pass
class AppleFactory(AbstractFactory):
"""生产苹果"""
def get_fruit(self):
return Apple()
class BananaFactory(AbstractFactory):
"""生产香蕉"""
def get_fruit(self):
return Banana()
class OrangeFactory(AbstractFactory):
"""生产橘子"""
def get_fruit(self):
return Orange()
if __name__ == '__main__':
# 每个工厂负责生产自己的产品也避免了我们在新增产品时需要修改工厂的代码,而只要增加相应的工厂即可
instance_apple = AppleFactory().get_fruit()
instance_banana = BananaFactory().get_fruit()
instance_orange = OrangeFactory().get_fruit()
print(instance_apple)
print(instance_banana)
print(instance_orange)
class MaoXW_CC(object):
"""川菜-毛血旺"""
def __str__(self):
return "川菜-毛血旺"
class XiaoCR_CC(object):
"""川菜-小炒肉"""
def __str__(self):
return "川菜-小炒肉"
class MaoXW_XC(object):
"""湘菜-毛血旺"""
def __str__(self):
return "湘菜-毛血旺"
class XiaoCR_XC(object):
"""湘菜-小炒肉"""
def __str__(self):
return "湘菜-小炒肉"
class AbstractFactory(object):
"""
抽象工厂
既可以生产毛血旺,也可以生成小炒肉
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def product_maoxw(self):
pass
@abc.abstractmethod
def product_xiaocr(self):
pass
class CCFactory(AbstractFactory):
"""川菜馆"""
def product_maoxw(self):
return MaoXW_CC()
def product_xiaocr(self):
return XiaoCR_CC()
class XCFactory(AbstractFactory):
"""湘菜馆"""
def product_maoxw(self):
return MaoXW_XC()
def product_xiaocr(self):
return XiaoCR_XC()
if __name__ == '__main__':
# 川菜炒两个菜,分别是:毛血旺和小炒肉
maoxw_cc = CCFactory().product_maoxw()
xiaocr_cc = CCFactory().product_xiaocr()
print(maoxw_cc, xiaocr_cc)
maoxw_xc = XCFactory().product_maoxw()
xiaocr_xc = XCFactory().product_xiaocr()
print(maoxw_xc, xiaocr_xc)
4. 最后
单例模式和工厂模式是日常使用最为频繁的两种设计模式,下篇文章将聊聊后面 3 种设计模式