[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点之前离开公司”,那么只需要增加一个“强制下班状态”,然后改动一下“傍晚工作状态”就可以了。而这是不影响其他状态的代码的。

原文地址:https://www.cnblogs.com/CheeseZH/p/9458703.html

时间: 2024-11-05 22:54:50

[Python设计模式] 第16章 上班,干活,下班,加班——状态模式的相关文章

设计模式@第16章:模板方法模式

第16章:模板方法模式 一.豆浆制作问题 编写制作豆浆的程序,说明如下: 制作豆浆的流程 选材--->添加配料--->浸泡--->放到豆浆机打碎 通过添加不同的配料,可以制作出不同口味的豆浆 选材.浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的 请使用 模板方法模式 完成 (说明:因为模板方法模式,比较简单,很容易就想到这个方案,因此就直接使用, 不再使用传统的方案来引出模板方法模式 ) 二.模板方法模式基本介绍 基本介绍 模板方法模式(Template Method P

[Python设计模式] 第1章 计算器——简单工厂模式

写在前面的话 """ 读书的时候上过<设计模式>这一门课,当时使用的教材是程杰老师的<大话设计模式>,使用的语言是C#,学过课程之后初期深感面向对象思想的伟大,但是很少应用到实际开发中.后来我接触了Python,现在工作中用到最多的也是Python,或许是因为Python的便利性,我写的很多脚本/程序都还是面向过程编程,缺少面向对象的思想在里边.因此,我打算重读程杰老师的<大话设计模式>并用Python进行实践. ""&

[Python设计模式] 第6章 衣服搭配系统——装饰模式

题目 设计一个控制台程序,可以给人搭配嘻哈风格(T恤,垮裤,运动鞋)或白领风格(西装,领带,皮鞋)的衣服并展示,类似QQ秀那样的. 基础版本 class Person(): def __init__(self, name): self.name = name def wear_T_shirts(self): print("T恤") def wear_big_trouser(self): print("垮裤") def wear_sneakers(self): pri

[Python设计模式] 第18章 游戏角色备份——备忘录模式

github地址:https://github.com/cheesezh/python_design_patterns 题目 用代码模拟以下场景,一个游戏角色有生命力,攻击力,防御力等数据,在打Boss前后的数据值会发生变化,如果玩家挑战Boss失败,我们允许玩家可以将游戏数据恢复到与Boss决斗之前的状态. 基础版本 class GameRole(): def __init__(self): self.vitality = 0 self.attack = 0 self.defense = 0

[Python设计模式] 第17章 程序中的翻译官——适配器模式

github地址:https://github.com/cheesezh/python_design_patterns 适配器模式 适配器模式,将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作[DP]. 当系统的数据和行为都正确,但是接口不符时,我们应该考虑使用适配器模式,目的就是使控制范围之外的一个原有对象与某个接口匹配.适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况. class Targe

[Python设计模式] 第15章 如何兼容各种DB——抽象工厂模式

github地址:https://github.com/cheesezh/python_design_patterns 题目 如何让一个程序,可以灵活替换数据库? 基础版本 class User(): """ 用户类,模拟用户表,假设只有ID和name两个字段 """ def __init__(self): self.id = None self.name = None class SqlServerUser(): ""&qu

LPTHW 笨方法学习python 16章

根据16章的内容作了一些扩展. 比如,判断文件如果存在,就在文件后追加,如不存在则创建. 同时借鉴了shell命令中类似 cat <<EOF > test的方法,提示用户输入一个结尾符. 现在有一个小坑,怎么使用python去读取一个文件的行数,原来有os.system("wc -l filename")倒是可以,但是windows下如何操作呢?回头补填. #!/usr/bin/env python # -*- coding:utf-8 -*- from sys im

设计模式之第16章-代理模式(Java实现)

设计模式之第16章-代理模式(Java实现) “现在朋友圈真是太让人蛋疼了啊.”“怎么说?”“一堆代理,各种卖东西的,看着好烦人.”“哎,删了呗.”“都是朋友,哪里好意思删啊.”“这倒也是...哎,迫于生计,没办法咯.还好我不玩.”“对了,你不就是代理的鼻祖么,身为代理模式,你作何感想.”“以代理之道还治代理之身啊.” 代理模式之自我介绍 最近出场率超级高,哦不,一直以来出场率都挺高的说的大名鼎鼎的模式,就是我-代理模式是也.有关我的定义如下:Provide a surrogate or pla

《Python学习手册 第五版》 -第16章 函数基础

前面的章节讲解的是一些基础数据类型.基本语句使用和一些文档查看的内容,这些都是一些基础,其实还谈不上入门,只有了解了函数,才算入门 函数是编程里面使用最多的也是最基本的程序结构, 本章重点内容 1.函数 1)什么是函数? 2)为什么使用函数? 2.编写函数 1)函数的基本格式 2)定义和调用函数 3)函数的多态.局部变量 接下来针对本章重点,展开详细的说明 1.函数 1)什么是函数? 这里没有严格的定义,用通俗易懂的方式来说: 函数就是将一些语句集合在一起的组件,从而让他们能够不止一次的在程序中