例子1
源码: state3.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
状态模式
换一个博客发布审批流程.
创建文章->请求审阅->审阅->审批成功->发布.
创建文章->请求审阅->审阅->审批失败->编辑文章->请求审阅->审阅->审批成功->发布.
"""
from __future__ import print_function
class State(object):
def __init__(self):
self.approve_times = 0
self.review_times = 0
class Article(State):
def __init__(self, blog):
super(Article, self).__init__()
self.name = "起草状态"
self.title = None
self.content = None
self.blog = blog
def add_content(self, title, content):
self.title = title
self.content = content
def edit_content(self, title, content):
self.title = title
self.content = content
def request_review(self):
self.blog.state = self.blog.pending
return self.blog.state
class Pending(State):
def __init__(self, blog):
super(Pending, self).__init__()
self.name = "待审核状态"
self.content = None
self.blog = blog
self.target = None
def do_review(self):
self.review_times += 1
def approve(self):
self.approve_times += 1
def publish(self):
if self.approve_times:
return Result.ok
else:
self.blog.state = self.blog.article
return Result.err
def reject(self):
self.blog.state = self.blog.article
return Result.err
class Result(object):
ok = "审核成功"
err = "审核失败"
class Blog(object):
def __init__(self):
self.article = Article(self)
self.pending = Pending(self)
self.state = self.article
def create_article(self, title, content):
self.article.add_content(title, content)
return self.state
if __name__ == '__main__':
# 测试: 通过流程.
blog = Blog()
article = blog.create_article("first blog", "hello world!") # 创建文章
pending = article.request_review() # 请求审阅
pending.do_review() # 审阅
pending.approve() # 审核通过
result = pending.publish() # 发布文章
assert result == Result.ok
# 测试 拒绝流程
blog = Blog()
article = blog.create_article("second blog", "hello world!")
pending = article.request_review()
pending.do_review()
result = pending.reject()
if result != Result.err:
raise RuntimeError(Result.err)
article.edit_content("second blog", "hello world again!")
pending = article.request_review()
pending.do_review()
pending.approve()
result = pending.publish()
assert result == Result.ok
# 测试: 没同意就直接发布, 返回错误Result.err枚举
blog = Blog()
article = blog.create_article("second blog", "hello world!")
pending = article.request_review()
pending.do_review()
result = pending.publish()
assert result == Result.err
例子2
源码: state2.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
状态模式
状态模式允许我们在程序运行时改变对象的表现.
状态模式隶属于行为模式: 根据不同的行为去改变状态, 由不同的状态操控不同的表现.
下面的这个例子是 模拟 AM/FM 收音机 提供了两个按钮: 频道切换, 电台切换.
频道: AM 和 FM 着两种.
电台: 103.9, 101.7 很多种.
我们人为的去触发不同的按钮, 改变收音机内部状态, 而收音机通过不同的状态去操控
不同的表现.
Implementation of the state pattern
http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
*TL;DR80
Implements state as a derived class of the state pattern interface.
Implements state transitions by invoking methods from the pattern's superclass.
"""
from __future__ import print_function
class State(object):
"""
State 对象提供了基本抽象, 所谓的基本抽象就是,
它定义了参数radio必须提供, 因此所有State的子类
对外也是要求radio参数必须提供.
State 指定了初始化应该要有的对象属性值, 但是这些
属性值是无效的属性值, 应再子类中各自分别提供.
State 对象还定义了scan默认实现方法, 所有State的
子类对象默认都会拥有这个方法.
scan 方法所提供的能力是, 在相同对象内提供不
同电台的切换能力, 并打印出电台切换后的信息.
对象指的是下面的: AmState 和 FmState 对象.
"""
def __init__(self, radio):
self.pos = 0 # 记录当前所在电台位置
self.name = None
self.stations = [] # 所有电台列表
self.radio = radio
def scan(self):
self.pos += 1
if self.pos == len(self.stations): # 如果电台已经是最后一个, 那么就回到第0个.
self.pos = 0
print(u"Scanning... Station is %s %s" %
(self.stations[self.pos], self.name))
def toggle_amfm(self):
prepare = self.radio.toggle[self.radio.state]
print(u"Switching to {}".format(prepare.name))
self.radio.state = prepare
class AmState(State):
"""
AmState 对象继承了 State 对象, 因此它初始化参数radio
必须与State对象保持一致, 并且使用super().__init__()语法
将参数向上传递, 然后在定义其他对象属性.
self.stations: 电台
self.pos: 当前电台位置
self.name: AM 频道
toggle_amfm 方法 将 频道切换到 FM 频道.
"""
def __init__(self, radio):
super(AmState, self).__init__(radio)
self.stations = ["1250", "1380", "1510"]
self.pos = 0
self.name = "AM"
class FmState(State):
"""
FmState 对象继承了 State 对象, 因此它初始化参数radio
必须与State对象保持一致, 并且使用super().__init__()语法
将参数向上传递, 然后在定义其他对象属性.
self.stations: 电台
self.pos: 当前电台位置
self.name: FM 频道
toggle_amfm 方法 将 频道切换到 AM 频道.
"""
def __init__(self, radio):
super(FmState, self).__init__(radio)
self.stations = ["81.3", "89.1", "103.9"]
self.pos = 0
self.name = "FM"
class Radio(object):
# """A radio. It has a scan button, and an AM/FM toggle switch."""
"""
Radio 收音机对象针对两个按钮进行的不同实现.
self.amstate: AM频道对象
self.fmstate: FM频道对象
self.state: 当前是哪个频道
这三个对象属性, 的代码组织在设计模式里面被称为组合, 将不同的对象组合到一起.
toggle_amfm 方法负责运行当前频道的 toggle_amfm 的方法(完成频道切换行为).
scan 方法负责运行当前频道的 scan 方法(完成电台切换行为).
"""
def __init__(self):
"""We have an AM state and an FM state"""
self.amstate = AmState(self)
self.fmstate = FmState(self)
self.state = self.amstate # 核心在这里
self.toggle = {
self.amstate: self.fmstate,
self.fmstate: self.amstate
}
def toggle_amfm(self):
self.state.toggle_amfm() # 核心在这里
def scan(self):
self.state.scan() # 核心在这里
# Test our radio out
if __name__ == '__main__':
radio = Radio()
actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2
actions *= 2
# 这里比较难理解, 可以换一种方式来看:
# actions = []
# actions.append(radio.scan)
# actions.append(radio.scan)
# actions.append(radio.toggle_amfm)
# actions.append(radio.scan)
# actions.append(radio.scan)
# actions.append(radio.scan)
# actions.append(radio.scan)
# actions.append(radio.toggle_amfm)
# actions.append(radio.scan)
# actions.append(radio.scan)
for action in actions:
action() # 这里开始模拟触发按钮行为.
### OUTPUT ###
# Scanning... Station is 1380 AM
# Scanning... Station is 1510 AM
# Switching to FM
# Scanning... Station is 89.1 FM
# Scanning... Station is 103.9 FM
# Scanning... Station is 81.3 FM
# Scanning... Station is 89.1 FM
# Switching to AM
# Scanning... Station is 1250 AM
# Scanning... Station is 1380 AM