python的out模式_python状态模式

标签: python 设计模式

引子

状态模式确实很好玩,我是说书上的例子确实很好玩,我对着电脑玩了好长时间,但是想说清楚还真不太容易,先从容易的开始吧

糖果机

糖果机操作的流程如下所示,这张图也叫状态图,它显示了糖果机的工作流程及状态流程

状态图1

其中一共有四个状态

售出糖果

糖果售罄

有25分钱

没有25分钱

操作糖果机会设计四个动作

投入25分钱

退回25分钱

转动曲柄

发放糖果 这个动作是糖果机内部的动作,机器自己调用

一开始...

创建一个糖果机的类,包含了四种状态

class GumballMachine:

def __init__(self, count):

self.SOLD_OUT = 0 #糖果售罄状态

self.NO_QUARTER = 1 #没有25分钱状态

self.HAS_QUARTER = 2 #有25分钱状态

self.SOLD = 3 #售出糖果状态

self.state = self.SOLD_OUT #初始状态为`没有25分钱状态`

self.count = count #设置一个糖果数量变量,它为0时就是糖果售罄的状态

if self.count > 0: #此处如果糖果数大于0,则状态为初始状态

self.state = self.NO_QUARTER

接下来该怎么办呢?

按照上图,状态与状态之间是通过动作进行连接的,可以对每一个动作创建一个对应的方法,这些方法利用条件语句来决定在四个状态下的恰当行为

例如投入25分钱和这个动作在四种状态下糖果机的反应如下图

状态图2

动作代表当前执行的动作是投入25分钱

如果糖果机当前状态是没有25分钱,则糖果机行为是显示你投入了25分钱,之后状态要切换到有25分钱

如果糖果机当前状态是有25分钱,则糖果机行为是显示投多了

如果糖果机当前状态是糖果售罄,则糖果机行为是显示售光了,不能投了

如果糖果机当前状态是售出糖果,则糖果机行为是显示投太快了,稍等,因为售出糖果后,糖果机要恢复到初始状态没有25分钱

剩下的动作和这个没有什么区别,每个动作都有一个状态转换的步骤

代码

def insertQuarter(self): #投入25分钱动作

if self.state == self.HAS_QUARTER:

print("You cannot insert another quarter")

elif self.state == self.NO_QUARTER:

self.state = self.HAS_QUARTER

print("You insert a quarter")

elif self.state == self.SOLD_OUT:

print("You can't insert a quarter, the machine is sold out")

elif self.state == self.SOLD:

print("Please wait, we're already giving you a gumball")

def ejectQuarter(self): #退回25分钱动作

if self.state == self.HAS_QUARTER:

print("Quarter returned")

self.state = self.NO_QUARTER

elif self.state == self.NO_QUARTER:

print("You haven't inserted a quarter")

elif self.state == self.SOLD:

print("Sorry, you already turned the crank")

elif self.state == self.SOLD_OUT:

print("You can't eject, you haven't inserted a quarter yet")

def turnCrank(self): #转动曲柄动作

if self.state == self.SOLD:

print("Turning twice doesn't get you another gumball!")

elif self.state == self.NO_QUARTER:

print("You turned, but there's no quarter")

elif self.state == self.SOLD_OUT:

print("You turned, but there's no gumball")

elif self.state == self.HAS_QUARTER:

print("You turned....")

self.state = self.SOLD

self.dispense() #切换到发放糖果这个内部动作上

def dispense(self): #发放糖果动作

if self.state == self.SOLD:

print("A gumball comes rolling out the slot")

self.count = self.count - 1 #发放一次糖果,糖果数量要减1

if self.count == 0: #糖果数量为0了,切换到糖果售罄的状态

print("Oops, out of gumballs")

self.state = self.SOLD_OUT

else:

self.state = self.NO_QUARTER

elif self.state == self.NO_QUARTER:

print("You need to pay first")

elif self.state == self.SOLD_OUT:

print("No gumball dispense")

elif self.state == self.HAS_QUARTER:

print("No gumball dispense")

玩一玩....

可以增加两个方法,玩的时候实时查看当前状态和糖果数量

def getCount(self):

print(self.count)

def getState(self):

print(self.state)

按照下面方法玩

def main():

gumballMachine = GumballMachine(2)

gumballMachine.getCount()

gumballMachine.getState()

print("=====================================================")

gumballMachine.insertQuarter()

gumballMachine.getState()

gumballMachine.ejectQuarter()

gumballMachine.ejectQuarter()

gumballMachine.insertQuarter()

gumballMachine.getState()

gumballMachine.turnCrank()

gumballMachine.getState()

gumballMachine.getCount()

gumballMachine.insertQuarter()

gumballMachine.turnCrank()

gumballMachine.getState()

print("=====================================================")

gumballMachine.turnCrank()

返回的结果

2 #两个糖果

1 #没有25分钱状态

=====================================================

You insert a quarter

2 #有25分钱状态

Quarter returned

You haven't inserted a quarter

You insert a quarter

2 #有25分钱状态

You turned....

A gumball comes rolling out the slot

1 #没有25分钱状态

1 #一个糖果

You insert a quarter

You turned....

A gumball comes rolling out the slot

Oops, out of gumballs

0 #糖果售罄状态

=====================================================

You turned, but there's no gumball

这个时候如果又来了一个状态怎么办...

按照状态2图,需要增加一个新的状态,之后在每个动作里面增加针对这个状态的行为,好像违反了好多设计原则。

新的方法

状态是变化的量,将变化封装起来,将动作和行为放到状态里,这样每个状态只要实现它自己的那套行为。

为每个状态创建状态类,这些类负责在对应的动作下糖果机的行为

将动作和行为委托给状态类

状态图3

之前的状态图2现在要变成这样了,用状态包裹所有的动作及对应的行为

有25分钱状态下,每一个动作对应不同的行为,在执行退回25钱动作后,状态切换到没有25分钱状态,在执行转动曲柄动作后,状态切换到没有25分钱状态。

代码

先看状态图3的代码实现

#有25分钱状态

class HasQuarterState(object):

def __init__(self, gumballMachine): #传入糖果机的实例

self.gumballMachine = gumballMachine

def insertQuarter(self): #投入25分钱动作

print("You cannot insert another quarter")

def ejectQuarter(self): #退出25分钱动作

print("Quarter returned")

self.gumballMachine.setState(self.gumballMachine.getNoQuarterState()) #之后糖果机的状

#态切换到没有25分钱状态

def turnCrank(self): #转动曲柄动作

print("You turned....")

self.gumballMachine.setState(self.gumballMachine.getSoldState()) #之后糖果机的状

#态切换到售出糖果状态

def dispense(self): #发放糖果动作,这是个内部动作,此处实现没有作用

print("No gumball dispense")

其他状态的代码也是类似

#糖果售罄状态

class SoldOutState(object):

def __init__(self, gumballMachine):

self.gumballMachine = gumballMachine

def insertQuarter(self):

print("You can't insert a quarter, the machine is sold out")

def ejectQuarter(self):

print("You can't eject, you haven't inserted a quarter yet")

def turnCrank(self):

print("You turned, but there's no gumball")

def dispense(self):

print("No gumball dispense")

#没有25分钱状态

class NoQuarterState(object):

def __init__(self, gumballMachine):

self.gumballMachine = gumballMachine

def insertQuarter(self):

print("You inserted a quarter")

self.gumballMachine.setState(self.gumballMachine.getHasQuarterState())

def ejectQuarter(self):

print("You haven't inserted a quarter")

def turnCrank(self):

print("You turned, but there's no quarter")

def dispense(self):

print("You need to pay first")

#售出糖果状态

class SoldState(object):

def __init__(self, gumballMachine):

self.gumballMachine = gumballMachine

def insertQuarter(self):

print("Please wait, we're already giving you a gumball")

def ejectQuarter(self):

print("Sorry, you already turned the crank")

def turnCrank(self):

print("Turning twice doesn't get you another gumball!")

def dispense(self):

self.gumballMachine.releaseBall()

if self.gumballMachine.getCount()>0:

self.gumballMachine.setState(self.gumballMachine.getNoQuarterState())

else:

print("Oops, out of gumballs")

self.gumballMachine.setState(self.gumballMachine.getSoldOutState())

看看糖果机的实现

#糖果机类

class GumballMachine:

def __init__(self, numberGumballs):

self.count = numberGumballs

#=========创建每一个状态的状态实例====================#

self.soldOutState = SoldOutState(self)

self.noQuarterState = NoQuarterState(self)

self.hasQuarterState = HasQuarterState(self)

self.soldState = SoldState(self)

#=========end=========================================#

if self.count > 0:

self.state = self.noQuarterState

#============每个状态的get方法和set方法===============#

def getSoldOutState(self):

return self.soldOutState

def getNoQuarterState(self):

return self.noQuarterState

def getHasQuarterState(self):

return self.hasQuarterState

def getSoldState(self):

return self.soldState

def setState(self, state):

self.state = state

#=========end=========================================#

#============将方法委托给当前的状态===================#

def insertQuarter(self):

self.state.insertQuarter()

def ejectQuarter(self):

self.state.ejectQuarter()

def turnCrank(self):

if self.state == self.hasQuarterState:

self.state.turnCrank()

self.state.dispense()

else:

self.state.turnCrank()

#=========end=========================================#

def releaseBall(self):

print("A gumball comes rolling out the slot...")

if self.count != 0:

self.count -= 1

#============检查状态和糖果数量的方法=================#

def getState(self):

print(self.state)

def getCount(self):

return self.count

还是用之前得测试代码,看看返回

2 #糖果数量

<__main__.noquarterstate object at> #当前状态

=====================================================

You inserted a quarter #行为

<__main__.hasquarterstate object at> #当前状态

Quarter returned #行为

You haven't inserted a quarter #行为

You inserted a quarter #行为

<__main__.hasquarterstate object at> #当前状态

You turned.... #行为

A gumball comes rolling out the slot... #行为

<__main__.noquarterstate object at> #当前状态

1 #糖果数量

You inserted a quarter #行为

You turned.... #行为

A gumball comes rolling out the slot... #行为

Oops, out of gumballs #行为

<__main__.soldoutstate object at> #当前状态

=====================================================

You turned, but there's no gumball #行为

看看执行图

初始状态是没有25分钱,执行投入25分钱动作

糖果机切换状态到第二步状态有25分钱,之后执行转动曲柄动作

糖果机切换状态到第三步状态售出糖果,之后执行发放糖果动作

如果糖果数目为0,则糖果机切换状态到第四步状态糖果售罄

糖果机动作和行为都委托给了每种状态,状态一变,糖果机的行为就是此种状态下的动作产生的行为了,这样一来,如果增加了一种状态,只要单独实现这个状态下糖果机所有的行为就OK了。

再来一个状态

增加一个游戏状态,转曲柄获取糖果的时候,有10%的机会能成为大赢家,获得附赠的一粒糖果,这个怎么搞?

增加一个状态winnerState

class WinnerState(object):

def __init__(self, gumballMachine):

self.gumballMachine = gumballMachine

def insertQuarter(self):

print("Please wait, we're already giving you a gumball")

def ejectQuarter(self):

print("Sorry, you already turned the crank")

def turnCrank(self):

print("Turning twice doesn't get you another gumball!")

# 你赢了,如果糖果没了,那就算了,只能白赢了;

def dispense(self):

print("You are winner! You get 2 gumball for youe quarter")

if self.gumballMachine.getCount()==0:

self.gumballMachine.setState(self.gumballMachine.getSoldOutState())

else:

self.gumballMachine.releaseBall()

if self.gumballMachine.getCount()>0:

self.gumballMachine.releaseBall()

self.gumballMachine.setState(self.gumballMachine.getNoQuarterState())

else:

print("Oops, out of gumballs")

self.gumballMachine.setState(self.gumballMachine.getSoldOutState())

随机数怎么整,random.randint这个就能实现,但是这个动作要增加在哪里呢,哪个状态下转动曲柄可以获得糖果,是有25分钱这个状态,只要将这个状态下的转曲柄动作稍微改动一下就OK了

def turnCrank(self):

print("You turned....")

#产生随机数

self.winner = random.randint(1, 100)

#这个数为1你就赢了

if self.winner == 1:

self.gumballMachine.setState(self.gumballMachine.getWinnerState())

else:

self.gumballMachine.setState(self.gumballMachine.getSoldState())

开始玩吧

def main():

gumballMachine = GumballMachine(100)

print(gumballMachine.getCount())

for i in range(5):

print("======================{0}====================".format(i+1))

gumballMachine.insertQuarter()

gumballMachine.turnCrank()

print(gumballMachine.getCount())

5次几率好像太小,应该中不了

======================1====================

You inserted a quarter

You turned....

You are winner! You get 2 gumball for youe quarter

A gumball comes rolling out the slot...

A gumball comes rolling out the slot...

======================2====================

You inserted a quarter

You turned....

A gumball comes rolling out the slot...

======================3====================

You inserted a quarter

You turned....

A gumball comes rolling out the slot...

======================4====================

You inserted a quarter

You turned....

A gumball comes rolling out the slot...

======================5====================

You inserted a quarter

You turned....

A gumball comes rolling out the slot...

94

靠!!!!!第一次就中了

定义

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值