成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

python設(shè)計(jì)模式-狀態(tài)模式

A Loity / 2325人閱讀

摘要:很明顯,有有分錢(qián)沒(méi)有分錢(qián)售出糖果糖果售罄四個(gè)狀態(tài),同時(shí)也對(duì)應(yīng)四個(gè)動(dòng)作投入分錢(qián),退回分錢(qián),轉(zhuǎn)動(dòng)曲柄和發(fā)放糖果。狀態(tài)模式的類(lèi)圖如下?tīng)顟B(tài)模式是將多個(gè)行為封裝在狀態(tài)對(duì)象中,的行為隨時(shí)可委托到其中一個(gè)狀態(tài)中。

問(wèn)題:有一個(gè)糖果公司需要設(shè)計(jì)一個(gè)糖果售賣(mài)機(jī),控制流程如下圖,需要怎么實(shí)現(xiàn)?

這是一個(gè)狀態(tài)圖,每個(gè)圓圈都是一種狀態(tài)。很明顯,有有25分錢(qián)、 沒(méi)有25分錢(qián)、 售出糖果、 糖果售罄四個(gè)狀態(tài),同時(shí)也對(duì)應(yīng)四個(gè)動(dòng)作投入25分錢(qián),退回25分錢(qián),轉(zhuǎn)動(dòng)曲柄發(fā)放糖果。

那如何從狀態(tài)圖得到真正的代碼呢?

簡(jiǎn)單代碼實(shí)現(xiàn)如下:

#! -*- coding: utf-8 -*-

class GumballMachine:

    # 找出所有狀態(tài),并創(chuàng)建實(shí)例變量來(lái)持有當(dāng)前狀態(tài),然后定義狀態(tài)的值
    STATE_SOLD_OUT = 0
    STATE_NO_QUARTER = 1
    STATE_HAS_QUARTER = 2
    STATE_SOLD = 3

    state = STATE_SOLD_OUT

    def __init__(self, count=0):
        self.count = count
        if count > 0:
            self.state = self.STATE_NO_QUARTER

    def __str__(self):
        return "Gumball machine current state: %s" % self.state

    def insert_quarter(self):
        # 投入25分錢(qián)
        if self.state == self.STATE_HAS_QUARTER: # 如果已經(jīng)投過(guò)
            print("You can"t insert another quarter")
        elif self.state == self.STATE_NO_QUARTER: # 如果沒(méi)有投過(guò)
            self.state = self.STATE_HAS_QUARTER
            print("You inserted a quarter")
        elif self.state == self.STATE_SOLD_OUT: # 如果已經(jīng)售罄
            print("You can"t insert a quarter, the machine is sold out")
        elif self.state == self.STATE_SOLD: # 如果剛剛買(mǎi)了糖果
            print("Please wait, we"re already giving you a gumball")

    def eject_quarter(self):
        # 退回25分
        if self.state == self.STATE_HAS_QUARTER:
            print("Quarter returned")
            self.state = self.STATE_NO_QUARTER
        elif self.state == self.STATE_NO_QUARTER:
            print("You haven"t inserted a quarter")
        elif self.state == self.STATE_SOLD:
            print("Sorry, you alread turned the crank")
        elif self.state == self.SOLD_OUT:
            print("You can"t eject, you haven"t inserted")

    def turn_crank(self):
        # 轉(zhuǎn)動(dòng)曲柄
        if self.state == self.STATE_SOLD:
            print("Turning twice doesn"t get you another gumball")
        elif self.state == self.STATE_NO_QUARTER:
            print("You turned but there"s no quarter")
        elif self.state == self.STATE_SOLD_OUT:
            print("You turned, but there are no gumballs")
        elif self.state == self.STATE_HAS_QUARTER:
            print("You turned...")
            self.state = self.STATE_SOLD
            self.dispense()
    
    def dispense(self):
        # 發(fā)放糖果
        if self.state == self.STATE_SOLD:
            print("A gumball comes rolling out the slot")
            self.count -= 1
            if self.count == 0:
                self.state = self.STATE_SOLD_OUT
            else:
                self.state = self.STATE_NO_QUARTER
        elif self.state == self.STATE_NO_QUARTER:
            print("You need to pay first")
        elif self.state == self.STATE_SOLD_OUT:
            print("No gumball dispensed")
        elif self.state == self.STATE_HAS_QUARTER:
            print("No gumball dispensed")


if __name__ == "__main__":
    # 以下是代碼測(cè)試
    gumball_machine = GumballMachine(5) # 裝入5 個(gè)糖果
    print(gumball_machine)

    gumball_machine.insert_quarter() # 投入25分錢(qián)
    gumball_machine.turn_crank() # 轉(zhuǎn)動(dòng)曲柄
    print(gumball_machine)

    gumball_machine.insert_quarter() #投入25分錢(qián)
    gumball_machine.eject_quarter()  # 退錢(qián)
    gumball_machine.turn_crank()     # 轉(zhuǎn)動(dòng)曲柄

    print(gumball_machine)
    
    gumball_machine.insert_quarter() # 投入25分錢(qián)
    gumball_machine.turn_crank() # 轉(zhuǎn)動(dòng)曲柄 
    gumball_machine.insert_quarter() # 投入25分錢(qián) 
    gumball_machine.turn_crank()  # 轉(zhuǎn)動(dòng)曲柄
    gumball_machine.eject_quarter() # 退錢(qián)

    print(gumball_machine)

這段代碼有幾個(gè)問(wèn)題:

沒(méi)有遵守開(kāi)放-關(guān)閉原則

更像是面向過(guò)程的設(shè)計(jì)

狀態(tài)轉(zhuǎn)化被埋藏在條件語(yǔ)句中

未來(lái)加入新的需求,需要改動(dòng)的較多,不易維護(hù),可能會(huì)出bug

如何改進(jìn)呢?

考慮封裝變化,把每個(gè)狀態(tài)的行為都放在各自的類(lèi)中,每個(gè)狀態(tài)只要實(shí)現(xiàn)自己的動(dòng)作,用加入新類(lèi)的方式來(lái)實(shí)現(xiàn)新?tīng)顟B(tài)的加入。

定義State 父類(lèi),在這個(gè)類(lèi)中,糖果機(jī)的每個(gè)動(dòng)作都有一個(gè)應(yīng)對(duì)的方法

為機(jī)器中的每個(gè)狀態(tài)實(shí)現(xiàn)狀態(tài)類(lèi),這些類(lèi)將負(fù)責(zé)在對(duì)應(yīng)的狀態(tài)下進(jìn)行機(jī)器的行為

擺脫舊的條件代碼,將動(dòng)作委托到狀態(tài)類(lèi)

新的實(shí)現(xiàn)代碼如下:

#! -*- coding: utf-8 -*-

class State:
    # 定義state基類(lèi)
    def insert_quarter(self):
        pass

    def eject_quarter(self):
        pass

    def turn_crank(self):
        pass

    def dispense(self):
        pass


class SoldOutState(State):
    # 繼承State 類(lèi)
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine

    def __str__(self):
        return "sold_out"

    def insert_quarter(self):
        print("You can"t insert a quarter, the machine is sold out")

    def eject_quarter(self):
        print("You can"t eject, you haven"t inserted a quarter yet")

    def turn_crank(self):
        print("You turned, but ther are no gumballs")

    def dispense(self):
        print("No gumball dispensed")


class SoldState(State):
    # 繼承State 類(lèi)
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine

    def __str__(self):
        return "sold"

    def insert_quarter(self):
        print("Please wait, we"re already giving you a gumball")

    def eject_quarter(self):
        print("Sorry, you already turned the crank")

    def turn_crank(self):
        print("Turning twice doesn"t get you another gumball")

    def dispense(self):
        self.gumball_machine.release_ball()
        if gumball_machine.count > 0:
            self.gumball_machine.state = self.gumball_machine.no_quarter_state
        else:
            print("Oops, out of gumballs!")
            self.gumball_machine.state = self.gumball_machine.soldout_state


class NoQuarterState(State):
    # 繼承State 類(lèi)
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine

    def __str__(self):
        return "no_quarter"

    def insert_quarter(self):
        # 投幣 并且改變狀態(tài)
        print("You inserted a quarter")
        self.gumball_machine.state = self.gumball_machine.has_quarter_state

    def eject_quarter(self):
        print("You haven"t insert a quarter")

    def turn_crank(self):
        print("You turned, but there"s no quarter")

    def dispense(self):
        print("You need to pay first")


class HasQuarterState(State):
    # 繼承State 類(lèi)
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine

    def __str__(self):
        return "has_quarter"

    def insert_quarter(self):
        print("You can"t insert another quarter")

    def eject_quarter(self):
        print("Quarter returned")
        self.gumball_machine.state = self.gumball_machine.no_quarter_state

    def turn_crank(self):
        print("You turned...")
        self.gumball_machine.state = self.gumball_machine.sold_state

    def dispense(self):
        print("No gumball dispensed")


class GumballMachine:

    def __init__(self, count=0):
        self.count = count
        # 找出所有狀態(tài),并創(chuàng)建實(shí)例變量來(lái)持有當(dāng)前狀態(tài),然后定義狀態(tài)的值
        self.soldout_state = SoldOutState(self)
        self.no_quarter_state = NoQuarterState(self)
        self.has_quarter_state = HasQuarterState(self)
        self.sold_state = SoldState(self)
        if count > 0:
            self.state = self.no_quarter_state
        else:
            self.state = self.soldout_state

    def __str__(self):
        return "Gumball machine current state: %s" % self.state

    def insert_quarter(self):
        # 投入25分錢(qián)
        self.state.insert_quarter()

    def eject_quarter(self):
        # 退回25分
        self.state.eject_quarter()
       
    def turn_crank(self):
        # 轉(zhuǎn)動(dòng)曲柄
        self.state.turn_crank()
        self.state.dispense()
    
    def release_ball(self):
        # 發(fā)放糖果
        print("A gumball comes rolling out the slot...")
        if self.count > 0:
            self.count -= 1
        
        
if __name__ == "__main__":
    # 以下是代碼測(cè)試
    gumball_machine = GumballMachine(5) # 裝入5 個(gè)糖果
    print(gumball_machine)

    gumball_machine.insert_quarter() # 投入25分錢(qián)
    gumball_machine.turn_crank() # 轉(zhuǎn)動(dòng)曲柄
    print(gumball_machine)

    gumball_machine.insert_quarter() #投入25分錢(qián)
    gumball_machine.eject_quarter()  # 退錢(qián)
    gumball_machine.turn_crank()     # 轉(zhuǎn)動(dòng)曲柄

    print(gumball_machine)
    
    gumball_machine.insert_quarter() # 投入25分錢(qián)
    gumball_machine.turn_crank() # 轉(zhuǎn)動(dòng)曲柄 
    gumball_machine.insert_quarter() # 投入25分錢(qián) 
    gumball_machine.turn_crank()  # 轉(zhuǎn)動(dòng)曲柄
    gumball_machine.eject_quarter() # 退錢(qián)

    print(gumball_machine)

重構(gòu)后的代碼相對(duì)于之前的代碼做了哪些事情呢?

將每個(gè)狀態(tài)的行為局部話到自己的類(lèi)中

刪除if 語(yǔ)句

狀態(tài)類(lèi)對(duì)修改關(guān)閉,對(duì)糖果季類(lèi)對(duì)擴(kuò)展開(kāi)放

下圖是剛初始狀態(tài)圖示:

上面重構(gòu)部分代碼使用的就是狀態(tài)模式:

定義
狀態(tài)模式: 狀態(tài)模式允許對(duì)象在內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來(lái)好像修改了它的類(lèi)。

狀態(tài)模式的類(lèi)圖如下:

狀態(tài)模式是將多個(gè)行為封裝在狀態(tài)對(duì)象中, context 的行為隨時(shí)可委托到其中一個(gè)狀態(tài)中。當(dāng)前狀態(tài)在不同的狀態(tài)對(duì)象中改變,以反映出context 內(nèi)部的狀態(tài),context 的行為也會(huì)隨之改變。
擴(kuò)展
如果,現(xiàn)在要在這四個(gè)狀態(tài)的基礎(chǔ)上再加一個(gè)狀態(tài)(購(gòu)買(mǎi)糖果后,有10%的概率再得一個(gè)),該如何實(shí)現(xiàn)呢?
# 添加WinnerState 類(lèi),只有dispense 方法不同,可以從SoldState 類(lèi)繼承
class WinnerState(SoldState):
    
    def __str__(self):
        return "winner"

    def dispense(self):
        print("You"re a WINNER! You get two gumballs for your quarter")
        self.gumball_machine.release_ball()
        if gumball_machine.count == 0:
            self.gumball_machine.state = self.gumball_machine.soldout_state
        else:
            self.gumball_machine.release_ball()
            if gumball_machine.count > 0:
                self.gumball_machine.state = self.gumball_machine.no_quarter_state
            else:
                print("Oops, out of gumballs!")
                self.gumball_machine.state = self.gumball_machine.soldout_state

# 修改turn_crank 方法
class HasQuarterState(State):
    ...
    def turn_crank(self):
        print("You turned...")
        winner = random.randint(0, 9)
        if winner == 4 and self.gumball_machine.count > 1: # 如果庫(kù)存大于 1 并且隨機(jī)數(shù)等于4(可以是0到9任意值)
            self.gumball_machine.state = self.gumball_machine.winner_state
        else:
            self.gumball_machine.state = self.gumball_machine.sold_state


# 在 GumballMachine 中初始化
class GumballMachine:

    def __init__(self, count=0):
        self.count = count
        # 找出所有狀態(tài),并創(chuàng)建實(shí)例變量來(lái)持有當(dāng)前狀態(tài),然后定義狀態(tài)的值
        ...
        self.winner_state = WinnerState(self)
        ...
總結(jié)

狀態(tài)模式允許一個(gè)對(duì)象給予內(nèi)部狀態(tài)而擁有不同的行為

狀態(tài)模式用類(lèi)代表狀態(tài)

Context 會(huì)將行為委托給當(dāng)前狀態(tài)對(duì)象

通過(guò)將每狀態(tài)封裝進(jìn)一個(gè)類(lèi),把改變局部化

狀態(tài)裝歡可以由State 類(lèi)或Context 類(lèi)控制

使用狀態(tài)模式會(huì)增加類(lèi)的數(shù)目

狀態(tài)類(lèi)可以被多個(gè)Context 實(shí)例共享


本文例子來(lái)自《Head First 設(shè)計(jì)模式》。

最后,感謝女朋友支持和包容,比??

也可以在公號(hào)輸入以下關(guān)鍵字獲取歷史文章:公號(hào)&小程序 | 設(shè)計(jì)模式 | 并發(fā)&協(xié)程

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/42910.html

相關(guān)文章

  • python設(shè)計(jì)模式-觀察者模式

    摘要:在程序設(shè)計(jì)中,觀察者模式通常被定義為觀察者模式定義了對(duì)象之間的一對(duì)多依賴(lài),這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài)是,它的所有依賴(lài)者都會(huì)收到通知并自動(dòng)更新。事件扮演發(fā)布者的角色,監(jiān)聽(tīng)者則扮演觀察者的角色。 題目:現(xiàn)在你有一個(gè)數(shù)字,默認(rèn)格式化程序是以十進(jìn)制格式展示此數(shù)值,但需要提供一個(gè)功能,這個(gè)程序要支持添加/注冊(cè)更多的格式化程序(比如:添加一個(gè)十六進(jìn)制格式化程序和一個(gè)二進(jìn)制格式化程序)。每次數(shù)值...

    terasum 評(píng)論0 收藏0
  • 設(shè)計(jì)模式手冊(cè)之狀態(tài)模式

    摘要:什么是狀態(tài)模式狀態(tài)模式對(duì)象行為是基于狀態(tài)來(lái)改變的。原文地址設(shè)計(jì)模式手冊(cè)之狀態(tài)模式優(yōu)缺點(diǎn)優(yōu)點(diǎn)封裝了轉(zhuǎn)化規(guī)則,對(duì)于大量分支語(yǔ)句,可以考慮使用狀態(tài)類(lèi)進(jìn)一步封裝。 1. 什么是狀態(tài)模式? 狀態(tài)模式:對(duì)象行為是基于狀態(tài)來(lái)改變的。 內(nèi)部的狀態(tài)轉(zhuǎn)化,導(dǎo)致了行為表現(xiàn)形式不同。所以,用戶在外面看起來(lái),好像是修改了行為。 Webpack4系列教程(17篇) + 設(shè)計(jì)模式手冊(cè)(16篇):GitHub地址 博...

    call_me_R 評(píng)論0 收藏0
  • 設(shè)計(jì)模式手冊(cè)之狀態(tài)模式

    摘要:什么是狀態(tài)模式狀態(tài)模式對(duì)象行為是基于狀態(tài)來(lái)改變的。原文地址設(shè)計(jì)模式手冊(cè)之狀態(tài)模式優(yōu)缺點(diǎn)優(yōu)點(diǎn)封裝了轉(zhuǎn)化規(guī)則,對(duì)于大量分支語(yǔ)句,可以考慮使用狀態(tài)類(lèi)進(jìn)一步封裝。 1. 什么是狀態(tài)模式? 狀態(tài)模式:對(duì)象行為是基于狀態(tài)來(lái)改變的。 內(nèi)部的狀態(tài)轉(zhuǎn)化,導(dǎo)致了行為表現(xiàn)形式不同。所以,用戶在外面看起來(lái),好像是修改了行為。 Webpack4系列教程(17篇) + 設(shè)計(jì)模式手冊(cè)(16篇):GitHub地址 博...

    Faremax 評(píng)論0 收藏0
  • Python學(xué)習(xí)之路25-使用一等函數(shù)實(shí)現(xiàn)設(shè)計(jì)模式

    摘要:本篇主要講述中使用函數(shù)來(lái)實(shí)現(xiàn)策略模式和命令模式,最后總結(jié)出這種做法背后的思想。 《流暢的Python》筆記。本篇主要講述Python中使用函數(shù)來(lái)實(shí)現(xiàn)策略模式和命令模式,最后總結(jié)出這種做法背后的思想。 1. 重構(gòu)策略模式 策略模式如果用面向?qū)ο蟮乃枷雭?lái)簡(jiǎn)單解釋的話,其實(shí)就是多態(tài)。父類(lèi)指向子類(lèi),根據(jù)子類(lèi)對(duì)同一方法的不同重寫(xiě),得到不同結(jié)果。 1.1 經(jīng)典的策略模式 下圖是經(jīng)典的策略模式的U...

    econi 評(píng)論0 收藏0
  • Python 中的進(jìn)程、線程、協(xié)程、同步、異步、回調(diào)

    摘要:進(jìn)程和線程究竟是什么東西傳統(tǒng)網(wǎng)絡(luò)服務(wù)模型是如何工作的協(xié)程和線程的關(guān)系和區(qū)別有哪些過(guò)程在什么時(shí)間發(fā)生在剛剛結(jié)束的上海站,來(lái)自七牛云存儲(chǔ)的高級(jí)工程師許智翔帶來(lái)了關(guān)于的分享中的進(jìn)程線程協(xié)程同步異步回調(diào)。使用紅黑樹(shù)管理就緒隊(duì)列。 進(jìn)程和線程究竟是什么東西?傳統(tǒng)網(wǎng)絡(luò)服務(wù)模型是如何工作的?協(xié)程和線程的關(guān)系和區(qū)別有哪些?IO過(guò)程在什么時(shí)間發(fā)生? 在剛剛結(jié)束的 PyCon2014 上海站,來(lái)自七牛云...

    Forest10 評(píng)論0 收藏0
  • 每天一個(gè)設(shè)計(jì)模式之享元模式

    摘要:作者按每天一個(gè)設(shè)計(jì)模式旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用和兩種語(yǔ)言實(shí)現(xiàn)。享元模式提醒我們將一個(gè)對(duì)象的屬性劃分為內(nèi)部和外部狀態(tài)。 作者按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用javascript和python兩種語(yǔ)言實(shí)現(xiàn)。誠(chéng)然,每種設(shè)計(jì)模式都有多種實(shí)現(xiàn)方式,但此小冊(cè)只記錄最直截了當(dāng)?shù)膶?shí)現(xiàn)方式 :) 個(gè)人技術(shù)博客-godbmw.com 歡迎來(lái)玩! 每周至少 1 篇原創(chuàng)...

    jone5679 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<