[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)是一种常用的软件设计模式 ...
随机推荐
- java大数相加
import java.math.BigInteger; import java.util.Scanner; public class Bignum{ public static void ma ...
- TCP/UDP 协议,和 HTTP、FTP、SMTP,区别及应用场景
一.OSI 模型 OSI 模型主要作为一个通用模型来做理论分析,而TCP/IP 协议模型是互联网的实际通讯协议,两者一般做映射分析,以下不做严格区分和声明(好吧,比较懒): OSI 整个模型层次大致可 ...
- Tomcat中文乱码解决办法
有时候发现自己将中文编码后还是会存在乱码的情况,解决办法就是在Server.xml中的Connector结点,配置 URIEncoding="UTF-8"即可
- Excel ——多表关联查询-vlookup
一.分组 需求: 在B列的右侧添加一列[消费分组]对B列的[月分组水平]进行分组,原始数据如下: 公式:在 C2 输入:“=VLOOKUP(B2,$E$1:$G$4,2,1)”,下拉填充. 提示:VL ...
- Python 豆瓣mv爬取
爬取网址:https://www.dbmeinv.com/ 豆瓣mv(现已更名) 注:自制力不好的同学,先去准备营养快线! import requests from bs4 import ...
- Pushing Boxes POJ - 1475 (嵌套bfs)
Imagine you are standing inside a two-dimensional maze composed of square cells which may or may not ...
- RedisCacheManager设置Value序列化器技巧
CacheManager基本配置 请参考博文:springboot2.0 redis EnableCaching的配置和使用 RedisCacheManager构造函数 /** * Construct ...
- macOS packages安装时的降级处理
一.降级安装 在制作macOS的pkg安装包时,一般新发布的程序版本会比旧版本更高.但是有的时候我们也希望在安装的时候,对程序的某些依赖库进行降级安装.比如高版本依赖库中出现了一些Bug,使用旧版本的 ...
- python数据结构之插入排序
插入排序(英语:Insertion Sort)是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,在从后向前扫描 ...
- SpringMVC(二四) 视图解析流程
目标方法无论返回的是string.ModelAndView.View,最终都被解析成modelAndView 关键的实现代码是在springmvc.xml配置文件中定义解析器. 参考代码如下: < ...