聊聊 Python 面试最常被问到的几种设计模式(下)
1. 前言
上篇文章 写到了 Python 最常用的 2 种设计模式,单例模式和工厂模式
本篇文章我们继续聊聊面试中,Python 面试经常被问到的设计模式,即:
- 构建者模式
- 代理模式
- 观察者模式
2. 构建者模式
构建者模式,是将一个复杂对象的构造与表现进行分离,利用多个步骤进行创建,同一个构建过程可用于创建多个不同的表现
简单来说,就是将一个复杂对象实例化的过程,按照自己的想法,一步步设置参数,定制一个我们需要的对象
构建者模式一般由 Director(指挥官)和 Builder(建设者)构成
其中:
Builder 用于定义目标对象部件的方法和参数
Director 用于构造一个 Builder 的接口,由 Director 去指导 Builder 生成一个复杂的对象
以购买一辆车( 包含:准备钱、看车、试驾、购买 4 个步骤)为例
首先,定义一个车的实体,并定义属性变量
class Car(object):
def __init__(self):
# 准备的钱
self.money = None
# 去哪里看车
self.address = None
# 试驾什么车
self.car_name = None
# 购买时间是
self.buy_time = None
def __str__(self):
return "准备了:%s,去%s看车,试驾了%s,下单了,购买时间是:%s" % (self.money, self.address, self.car_name, self.buy_time)
然后,创建一个 Builder,实例化一个 Car 对象;针对上面 4 个步骤,通过定义 4 个方法
分别是:准备多少钱、去哪里看车、试驾什么车、下单购买的时间
# 创建者
class CarBuilder(object):
def __init__(self):
self.car = Car()
def ready_money(self, money):
"""
准备的金额
:param money:
:return:
"""
self.car.money = money
sleep(0.5)
return self
def see_car(self, address):
"""
去哪里看车
:param address:
:return:
"""
self.car.address = address
sleep(0.5)
return self
def test_drive(self, car_name):
"""
试驾了什么车
:param car_name:
:return:
"""
self.car.car_name = car_name
sleep(0.5)
return self
def buy_car(self, buy_time):
"""
下单时间
:param buy_time:
:return:
"""
self.car.buy_time = buy_time
sleep(0.5)
return self
接着,创建 Director,创建 build 方法,使用 Builder 一步步构建一个车对象并返回
class Director(object):
def __init__(self):
self.builder = None
def build(self, builder):
self.builder = builder
self.builder.
ready_money("100万").
see_car("4S店").
test_drive("奥迪Q7").
buy_car("2020年8月1日")
# 返回构建的对象
return self.builder.car
最后使用的时候,只需要实例化一个 Builder 对象和 Director 对象,然后通过 Director 对象构建一个车对象即可
if __name__ == '__main__':
# 实例化一个构建者对象
car_builder = CarBuilder()
# 实例化一个负责人
director = Director()
# 构建的对象
car = director.build(car_builder)
print(car)
3. 代理模式
代理模式,会引入一个代理对象以代替真实的对象,解耦调用方和被调用方之间的联系
Python 中的实现方式也简单易懂
首先,我们定义一个真实对象实体类,并定义一个方法
class RealObject(object):
"""
实际对象
"""
def __init__(self, arg):
self.arg = arg
def foo(self):
print('参数值为:', self.arg)
然后,创建一个代理对象,在初始化函数 __init__ 中拿到真实对象的实例,定义一个相同的方法,并调用真实对象的方法
class ProxyObject(object):
"""
代理对象
"""
def __init__(self, real_object):
self.real_object = real_object
def foo(self):
# 实际对象调用
self.real_object.foo()
最后的使用方式如下:
if __name__ == '__main__':
# 实例化代理对象
proxy_object = ProxyObject(RealObject('AirPython'))
# 调用方法
proxy_object.foo()
如此,就实现了代理替换真实对象的目的
4. 观察者模式
观察者模式在 Python 中很常见,会定义了对象之间的一对多依赖关系,当被观察者(也称为主体对象)改变状态时,其他所有观察者都会收到事件并处理预定的事情
首先,我们创建一个观察者,在初始化函数中注册到被观察对象上,并且自定义一个更新函数
# 观察者
class Observer(object):
def __init__(self, subject):
# 初始化观察者,并注册
subject.register(self)
def update(self, arg1):
"""获取通知"""
print('观察者收到监听消息,参数为:', arg1)
然后,新建一个被观察对象,创建注册观察者、注销观察者方法
class Subject(object):
def __init__(self):
# 所有的观察者
self.observers = []
self.foo = None
def register(self, observer):
"""添加观察者"""
if observer not in self.observers:
self.observers.append(observer)
else:
print('已经存在,添加失败!')
def unregister(self, observer):
"""注销观察者"""
try:
self.observers.remove(observer)
except ValueError:
print('注销观察者失败')
接着,通过模拟修改变量的值,通知给所有的观察者
def notify(self):
"""通知所有的观察者"""
for item in self.observers:
item.update(self.foo)
def modify_value(self):
"""
修改变量的值
:return:
"""
self.foo = "公众号:AirPython"
# 修改后,通知所有观察者
self.notify()
最后的使用方式如下:
if __name__ == '__main__':
# 主体对象
subject = Subject()
# 观察者
observer = Observer(subject)
# 测试
subject.modify_value()
5. 最后
这两篇一共介绍了 5 种设计模式,它们在 Python 的各领域中被广泛使用,也是面试中最常被问到的几种设计模式
我已经将文中全部源码上传到后台,关注公众号后回复「 设计模式 」即可获得全部源码
如果你觉得文章还不错,请大家 点赞、分享、留言下,因为这将是我持续输出更多优质文章的最强动力!
- Python基础知识2:字典
- 桶式移位器
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.7 增加了一个js函数的分页方式。
- FireEye报告:揭露新型工控系统恶意软件TRITON
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.6 修改了几个小bug,使用演示。
- Invoke-PSImage:将PS脚本隐藏进PNG像素中并用一行指令去执行它
- linux的内存清理相关知识!
- 一个页面搞定几乎所有的列表需求的实现思路和一点代码。
- 实现 Table 的行交替颜色、选中行变色的一种方法。演示+源码
- 【知识】使用Python来学习数据科学的完整教程
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.4 增加了几个分页算法
- 虚拟时钟
- 正弦函数仿真
- 《你必须知道的.net》读书笔记 004 —— 1.4 多态的艺术
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Centos 7搭建Gitlab服务器超详细Centos 7搭建Gitlab服务器超详细(搭建成功)
- Netty之旅二:口口相传的高性能Netty到底是什么?
- 前端知识复习(一)
- Powershell运行脚本报错:此系统上禁止运行脚本
- git rebase解决合并冲突
- npm相关操作
- Angular html property的值如何被更新的
- Centos 7 使用mailx发送邮件
- Centos 7 备份MySQL
- Centos 7 备份MySQL/MongoDB并发邮件脚本
- Nginx启动报错:sbin/nginx: error while loading shared libraries: libpcre.so.1: cannot open shared object
- 有赞美业店铺装修前端解决方案
- nginx部署react项目
- Golang 标准库 限流器 time/rate 设计与实现
- Node搭建简易的UDP服务器