聊聊 Python 面试最常被问到的几种设计模式(上)
共 6401字,需浏览 13分钟
·
2021-11-12 16:00
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 种设计模式,希望大家在留言区捧个场支持一下,月底统计常来留言的同学送书,给个三连哈!你的支持,就是我原创的最佳动力!
星球的价格是一年88元,然后现在双11期间有优惠券20元,相当于是68一年,算下来每个月6块钱,连半杯奶茶的钱都不到,一天才2毛钱,非常划算。
推荐阅读:
入门: 最全的零基础学Python的问题 | 零基础学了8个月的Python | 实战项目 |学Python就是这条捷径
干货:爬取豆瓣短评,电影《后来的我们》 | 38年NBA最佳球员分析 | 从万众期待到口碑扑街!唐探3令人失望 | 笑看新倚天屠龙记 | 灯谜答题王 |用Python做个海量小姐姐素描图 |碟中谍这么火,我用机器学习做个迷你推荐系统电影
趣味:弹球游戏 | 九宫格 | 漂亮的花 | 两百行Python《天天酷跑》游戏!
AI: 会做诗的机器人 | 给图片上色 | 预测收入 | 碟中谍这么火,我用机器学习做个迷你推荐系统电影
小工具: Pdf转Word,轻松搞定表格和水印! | 一键把html网页保存为pdf!| 再见PDF提取收费! | 用90行代码打造最强PDF转换器,word、PPT、excel、markdown、html一键转换 | 制作一款钉钉低价机票提示器! |60行代码做了一个语音壁纸切换器天天看小姐姐!|
年度爆款文案