-
示例: 根据输入的颜色名, 产生对应的颜色的class
class Color(object): pass
class Red(Color): color = 'red'
class Green(Color): color = 'green'
class Factory(object):
def get_color(self, name): if name == 'red': return Red() if name == 'green': return Green() raise NotImplemented -
我用过工厂模式的地方:
给小荐开发时, 公司信息. 有个通用的CompanyInfo, 然后不同公司, 有ContactInfo, AddressInfo, ProductInfo. 他们的操作都是获取数据, 处理数据, 保存数据, 都有缓存机制. 然后一个请求过来, 不同的View就是调用了不同的Info, 然而其他处理机制都一样
- 传入参数,获取某个工厂
- 传入参数,通过工厂获取类
shapeFactory = FactoryProducer.getFactory("SHAPE")
shape = shapeFactory.getShare("CIRCLE")
shape.draw()
colorFactory = FactoryProducer.getFactory("COLOR")
color = colorFactory.getColor("RED")
color.fill()
示例 一个class只能实例化一次
- 我用过的地方:
开发交易日获取的时候, 因为要请求交易日列表并解析(慢),所以希望只初始化一次
现存了一个对象, 现在想要新增新的功能和接口. 所以需要一个adapter对象来更改现在对象的函数.
我们现在已经有了AudioPlayer播放mp3, 现在有了很厉害的Mp4Player和VlcPlayer, 需要把他的功能整合入AudioPlayer.
所以把其他的player封装成MediaAdapter, 提供统一的play接口
class VlcPlayer:
def play_vlc(self):
print("播放vlc")
class Mp4Player:
def play_mp4(self):
print("播放mp4")
class MediaAdapter:
def __init__(self, audio_type):
if audio_type == "vlc":
self.advanced_music_player = VlcPlayer()
elif audio_type == "mp4":
self.advanced_music_player = Mp4Player()
def play(self, audio_type, file_name):
if audio_type == "vlc":
self.advanced_music_player.play_vlc(file_name)
if audio_type == "mp4":
self.advanced_music_player.play_mp4(file_name)
class AudioPlayer(MediaAdapter):
def play(self, audio_type, file_name):
if audio_type == "mp3":
# 原来的函数不用改, 现在需要新的接口, 能传入audio_type
print("原来的播放mp3")
elif audio_type == "vlc" or audio_type == "mp4":
super().play(audio_type, file_name)
桥接模式 对于两个独立变化的维度,使用桥接模式再适合不过了。
形状和颜色组合类型为M X N, 如果只考虑形状, 把颜色类型当作参数传给Shape, 就能避免创建M X N个类.
为什么不把Red和Green当作参数传给shape? 因为这样就要求shape里面包含所有颜色的paint方法. 可能红色的要拿到血, 绿色的要除个草, 这样shape就太复杂了.
class ColorPaint:
def paint(self):
pass
class GreenPaint:
pass
class RedPaint:
pass
class Shape:
def __init__(self, shape_name, color_paint: ColorPaint):
self.color_paint = color_paint
def draw(self):
self.draw_outline()
self.color_paint.paint()
Shape("长方形", RedPaint).draw()
Shape("圆形", GreenPaint).draw()我做state-machine的时候,需要能够输入不同的backend来支持多个系统. 比如filelock, redislock, 他们的函数都不一样,在StateMachine里面只要知道expire和lock方法就行。所以就用了桥接模式
我做一个小区健康读检查系统的时候, 每个任务都有多个子任务. 每个任务的子任务字段一致,但是任务之间子任务字段不一致。所以创建一个大表保存所有子任务的共同字段。 同时各个任务的特有字段保存在单独的表格(dynamic-model创建)
每个handler, 都会有个next.
- 好处
- 每个责任链上的对象, 都只知道下一个, 结构简单
- 为什么不用函数呢, 每个责任链上都可以动态的更改下一步骤
- 事件冒泡, 可以方便地设置stoppop
- 事件冒泡, 可以方便地设置stoppop
- 事件冒泡, 可以方便地设置stoppop
console_logger = ConsoleLogger()
file_logger = FileLogger()
error_logger = ErrorLogger()
console_logger.setNextLogger(file_logger)
file_logger.setNextLogger(error_logger)
写一个model的时候, 经常会遇到model的更新后调用函数更新其他model数据的更新. 这个就要用中介者模式:
- 降低了类的复杂度,将一对多转化成了一对一.
- 各个类之间的解耦
- 符合迪米特原则
这个模式和责任链模式比, 就是标准的日志了. 同时设置3个handler, 一个负责print, 一个负责写入文件, 一个负责写入错误文件.
- 好处:
- 所有的观察者是平级的, 异步可以同时触发
- 解耦合, 避免了一个观察者的失误影响另外一个
- 需要循环调用时很方便
- 缺点:
- 小心遇到循环调用
状态模式和策略模式最大差别在于状态模式通过状态类来控制context
策略模式通过context里选择handler来处理, 个人觉得这个模式和策略模式相比,缺少了代码的复用性,理解起来不如策略模式直观
策略模式用于构建一系列的算法,对于不同的场景选用不同的策略。
做一个公司的任务流程,需要定时对每个任务进行处理。支持处理一类任务或者制定某个任务。
def handle(self):
strategy_info = {
"待执行": {
"pre_status": "待执行",
"next_status": "执行中",
"handler": self.handle_todo_task,
}
}[input("需要的策略")
for task in self.iter_queryset(status=strategy_info.pre_status):
try:
strategy_info['handler'].handler(task)
except SkipException:
continue
task.status = strategy_info['next_status']
task.save()用在嵌套构成tree的场景,通过组合模式把父亲和子元素做成一个类,复用代码
定义一个基础的骨架,然后其他的类都继承这个骨架.
在华为只用了模板模式, 处理数据转化.
之前在锐天, 用了模板模式定义handler, 同时对于通用的字段修改, 用工厂模式来定义handler处理的数据
## 不同的券商返回的交易数据格式有出入. 比如有的叫trade_datetime, 有的叫timestamp
## 基类就是对数据处理
class Handler:
def need_handle: ...
def handler: ...
def post_handle: ...
## 子类就是
class RenameHandler: ...
class TimestampToDatettimeHandler: ...
class DropColumnHandler: ...
## 又因为同样是rename,不同的券商要求的字段不一致,所以需要处理A券商时用
RenameHandler(map={"trade_datetime": "datetime"})
## 处理B券商时用
TimestampToDatettimeHandler(["timestamp"])
RenameHandler(map={"timestamp": "datetime"})