[Python设计模式] 第16章 上班,干活,下班,加班——状态模式
github地址:https://github.com/cheesezh/python_design_patterns
题目
用代码模拟一天的工作状态,上午状态好,中午想睡觉,下午渐恢复,加班苦煎熬。
基础版本——函数版
hour = 0
work_finished = False
def write_program():
if hour < 12:
print("当前时间: {} 点, 上午工作,精神百倍".format(hour))
elif hour < 13:
print("当前时间: {} 点, 饿了,午饭,犯困,午休".format(hour))
elif hour < 17:
print("当前时间: {} 点, 下午状态还可以,继续努力".format(hour))
elif work_finished == True:
print("当前时间: {} 点, 收工,下班".format(hour))
elif hour < 21:
print("当前时间: {} 点, 加班中,好累".format(hour))
else:
print("当前时间: {} 点, 不行了,睡着了".format(hour))
hour = 9
write_program()
hour = 10
write_program()
hour = 12
write_program()
hour = 13
write_program()
hour = 14
write_program()
hour = 17
work_finished = True
# work_finished = False
write_program()
hour = 19
write_program()
hour = 22
write_program()
当前时间: 9 点, 上午工作,精神百倍
当前时间: 10 点, 上午工作,精神百倍
当前时间: 12 点, 饿了,午饭,犯困,午休
当前时间: 13 点, 下午状态还可以,继续努力
当前时间: 14 点, 下午状态还可以,继续努力
当前时间: 17 点, 收工,下班
当前时间: 19 点, 收工,下班
当前时间: 22 点, 收工,下班
改进版本1.0——初步封装
class Work():
def __init__(self):
self.hour = 0
self.task_finished = False
def write_program(self):
if self.hour < 12:
print("当前时间: {} 点, 上午工作,精神百倍".format(self.hour))
elif self.hour < 13:
print("当前时间: {} 点, 饿了,午饭,犯困,午休".format(self.hour))
elif self.hour < 17:
print("当前时间: {} 点, 下午状态还可以,继续努力".format(self.hour))
elif self.work_finished == True:
print("当前时间: {} 点, 收工,下班".format(self.hour))
elif self.hour < 21:
print("当前时间: {} 点, 加班中,好累".format(self.hour))
else:
print("当前时间: {} 点, 不行了,睡着了".format(self.hour))
work = Work()
work.hour = 9
work.write_program()
work.hour = 10
work.write_program()
work.hour = 12
work.write_program()
work.hour = 13
work.write_program()
work.hour = 14
work.write_program()
work.hour = 17
work.work_finished = True
# work_finished = False
work.write_program()
work.hour = 19
work.write_program()
work.hour = 22
work.write_program()
当前时间: 9 点, 上午工作,精神百倍
当前时间: 10 点, 上午工作,精神百倍
当前时间: 12 点, 饿了,午饭,犯困,午休
当前时间: 13 点, 下午状态还可以,继续努力
当前时间: 14 点, 下午状态还可以,继续努力
当前时间: 17 点, 收工,下班
当前时间: 19 点, 收工,下班
当前时间: 22 点, 收工,下班
点评
- 这个类中的write_program方法过长,而且有很多判断分支,意味着它的责任过大了。面向对象设计其实就是希望做到代码的责任分解。所以这个类违背了
单一职责原则; - 此外,write_program方法里有这么多判断,使得任何需求的改动或增加,都需要去更改这个方法。所以这个类也违背了
开放-封闭原则;
状态模式
状态模式,当一个对象的内在状态改变是允许改变其行为,这个对象看起来像是改变了其类。[DP]
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
from abc import ABCMeta, abstractmethod
class State():
__metaclass__ = ABCMeta
@abstractmethod
def handle(self, context):
pass
class StateA(State):
def handle(self, context):
context.set_state(StateB())
class StateB(State):
def handle(self, context):
context.set_state(StateA())
class Context():
def __init__(self, state):
self.state = state
def set_state(self, state):
self.state = state
print("当前状态: {}".format(self.state.__class__))
def request(self):
self.state.handle(self) # 精髓
def main():
context = Context(StateA())
context.request()
context.request()
context.request()
context.request()
main()
当前状态: <class '__main__.StateB'>
当前状态: <class '__main__.StateA'>
当前状态: <class '__main__.StateB'>
当前状态: <class '__main__.StateA'>
状态模式的好处与用处
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。[DP]就是将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcretState中,所以通过定义新的子类可以很容易的增加新的状态和转换[DP]。这样做的目的就是为了消除庞大的条件分支语句,大的分支判断会使得它们难以修改和扩展。状态模式通过把各种状态转移逻辑分不到State的子类之间,来减少相互之间的依赖。
什么时候需要考虑使用状态模式呢?当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为,就可以使用状态模式。另外,如果业务需求某项业务有多个状态,通常都是一些枚举常量,状态的变化都是依靠大量的分支判断语句来实现,此时应该考虑将每一种业务状态定义为一个State子类,这样这些对象就可以不依赖于其他对象而独立变化了,如果某天客户需求改了,增加或减少业务状态或改变状态流程,都不是困难了。
改进版本2.0——状态模式
from abc import ABCMeta, abstractmethod
class State():
__metaclass__ = ABCMeta
@abstractmethod
def write_program(self, work):
pass
class ForenoonState(State):
def write_program(self, work):
if work.hour < 12:
print("当前时间: {} 点, 上午工作,精神百倍".format(work.hour))
else:
work.set_state(NoonState())
work.write_program()
class NoonState(State):
def write_program(self, work):
if work.hour < 13:
print("当前时间: {} 点, 饿了,午饭,犯困,午休".format(work.hour))
else:
work.set_state(AfternoonState())
work.write_program()
class AfternoonState(State):
def write_program(self, work):
if work.hour < 17:
print("当前时间: {} 点, 下午状态还可以,继续努力".format(work.hour))
else:
work.set_state(EveningState())
work.write_program()
class EveningState(State):
def write_program(self, work):
if work.task_finished == True:
work.set_state(RestState())
work.write_program()
elif work.hour < 21:
print("当前时间: {} 点, 加班中,好累".format(work.hour))
else:
work.set_state(SleepingState())
work.write_program()
class SleepingState(State):
def write_program(self, work):
print("当前时间: {} 点, 不行了,睡着了".format(work.hour))
class RestState(State):
def write_program(self, work):
print("当前时间: {} 点, 收工,下班".format(work.hour))
class Work():
def __init__(self, state):
self.state = state
self.hour = 0
self.task_finished = False
def set_state(self, state):
self.state = state
def write_program(self):
self.state.write_program(self) # 精髓
work = Work(ForenoonState())
work.hour = 9
work.write_program()
work.hour = 10
work.write_program()
work.hour = 12
work.write_program()
work.hour = 13
work.write_program()
work.hour = 14
work.write_program()
work.hour = 17
work.work_finished = True
# work_finished = False
work.write_program()
work.hour = 19
work.write_program()
work.hour = 22
work.write_program()
当前时间: 9 点, 上午工作,精神百倍
当前时间: 10 点, 上午工作,精神百倍
当前时间: 12 点, 饿了,午饭,犯困,午休
当前时间: 13 点, 下午状态还可以,继续努力
当前时间: 14 点, 下午状态还可以,继续努力
当前时间: 17 点, 加班中,好累
当前时间: 19 点, 加班中,好累
当前时间: 22 点, 不行了,睡着了
点评
假如老板规定“员工必须在20点之前离开公司”,那么只需要增加一个“强制下班状态”,然后改动一下“傍晚工作状态”就可以了。而这是不影响其他状态的代码的。
[Python设计模式] 第16章 上班,干活,下班,加班——状态模式的更多相关文章
- [Python设计模式] 第22章 手机型号&软件版本——桥接模式
github地址:https://github.com/cheesezh/python_design_patterns 紧耦合程序演化 题目1 编程模拟以下情景,有一个N品牌手机,在上边玩一个小游戏. ...
- [Python设计模式] 第25章 联合国维护世界和平——中介者模式
github地址:https://github.com/cheesezh/python_design_patterns 题目背景 联合国在世界上就是中介者的角色,各国之间的关系复杂,类似不同的对象和对 ...
- [Python设计模式] 第23章 烤串的哲学——命令模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟,顾客直接向烤串师傅提需求. class Barbecuer( ...
- [Python设计模式] 第12章 基金理财更省事——外观模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟股民直接炒股的代码,比如股民投资了股票1,股票2,股票3,国债 ...
- [Python设计模式] 第10章 怎么出试卷?——模版方法模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 小时候数学老师的随堂测验,都是老师在黑板上写题目,学生在下边抄,然后再做题 ...
- [Python设计模式] 第2章 商场收银软件——策略模式
github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计 ...
- 《Think Python》第16章学习笔记
目录 <Think Python>第16章学习笔记 16.1 Time 16.2 纯函数(Pure functions) 16.3 修改器(Modifiers) 16.4 原型 vs. 方 ...
- [Python设计模式] 第1章 计算器——简单工厂模式
github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...
- [Python设计模式] 第21章 计划生育——单例模式
github地址:https://github.com/cheesezh/python_design_patterns 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式 ...
随机推荐
- 月薪3万的python程序员都看了这本书
想必大家都看过吧 Python编程从入门到实践 全书共有20章,书中的简介如下: 本书旨在让你尽快学会 Python ,以便能够编写能正确运行的程序 —— 游戏.数据可视化和 Web 应用程序,同时掌 ...
- LoadRunner录制协议的选择
1.选择协议(提高测试结果的准确性) New Single Protocol Script:单协议脚本,选择一种主协议进行测试 New Multiple Protocol Script:多协议脚本,选 ...
- 学生成绩管理系统C++
今天晚上终于做完了学生成绩管理系统!激动!开心!!!哈哈哈~~~~ 总共298行代码,第一次写这么多. 其中遇到了好多困难,也烦恼了好久,不过最终都解决了! 做了之后果然,满满的成就感!抑制不住的兴奋 ...
- Beautifulsoup官方文档
Beautiful Soup 中文文档 原文 by Leonard Richardson (leonardr@segfault.org) 翻译 by Richie Yan (richieyan@gma ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- IDEA中的常用设置
ps:对于开发工具,不同的开发人员有不同的设置喜好,这里介绍的是我个人的配置,不喜勿喷. Appearance:个人喜欢全黑主题,雅黑字体 背景图片, 效果如下,编写代码的时候有个自己喜欢的背景图片, ...
- Markdown使用简介 及 学习资源整理
Markdown资源整理 官网 http://daringfireball.net/projects/markdown/ http://jgm.github.io/stmd/spec.html htt ...
- LINUX文件及目录管理命令基础(2)
Linux文件类型 文件作为Linux操作系统中最常见的对象,在系统中被分为了多种类型 如下: - 普通文件 d 目录 l 链接 b 块设备 c 字符设备 p 管道设备 s 套接字文件 Linux目录 ...
- BZOJ3877 : [Ahoi2014&Jsoi2014]保龄球
考虑从前往后放所有轮. 如果上一轮是全中: 那么这一轮如果是补中,一定放第一次最小的,这样可以让第一次大的放在其它补中之后. 如果这一轮是失误,那么一定放总分最大的. 如果上一轮是补中: 这一轮一定放 ...
- 关于在ViewPager的子页面中不能跳转的问题
关于在ViewPager的子页面中不能跳转的问题 什么是ViewPager? 相信很多人使用过微信,其实微信的四个子页面:微信.通讯录.发现.我以及下面的引导空间就是ViewPager. 出现的问题: ...