日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 设计模式之状态模式

發布時間:2024/9/30 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 设计模式之状态模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、了解狀態模式

1.1 什么是狀態模式

狀態模式允許對象在內部狀態改變時改變它的行為,對象看起來好像修改了它自己的類。

狀態模式將狀態封裝為獨立的類,并將動作委托到代表當前狀態的對象。

1.2 狀態模式組成結構

  • 上下文 (Context):用戶對象,擁有(聚合)一個 State 類型的成員,以標識對象的當前狀態。
  • 抽象狀態 (State):接口或基類,封裝與 Context 的特定狀態相關的行為。
  • 具體狀態 (ConcreteState):接口實現類或子類,實現了一個與 Context 某個狀態相關的行為。

1.3 狀態模式 UML 圖解

1.4 狀態模式與策略模式

如果對策略模式也了解的話,你會發現狀態模式的類圖與策略模式的類圖幾乎是一樣的。它們之間有什么關系嗎?
PS:策略模式具體博文http://blog.csdn.net/codejas/article/details/79077186

雖然狀態模式與策略模式的類圖是一樣的,但是它們兩個的“意圖”是明顯不一樣的。

對于狀態模式而言,我們將一群行為封裝在狀態對象中,context 的行為隨時可委托到那些狀態對象中的一個。隨著時間的流逝,當前狀態在狀態對象集合中游走改變,以反映出 context 內部的狀態,因此,context 的行為也會隨著改變。但是 context 的客戶對于狀態對象的了解程度不多,甚至根本是渾然不知。

而對于策略模式而言,客戶通常主動指定 context 所需要的策略對象是哪一個。策略模式雖然可以讓我們的代碼更有彈性,但是對于某個 context 對象來說,通常都只有一個最適當的策略對象。

1.5 狀態模式應用場景

  • 一個對象的行為取決于它的狀態,并且它必須在運行時刻根據狀態改變它的行為。
  • 一個操作中含有龐大的多分支結構,并且這些分支決定于對象的狀態。

二、狀態模式具體應用

2.1 問題描述

糖果機:一種新型糖果機的實現控制流程如圖所示,現在需要我們用 Java 語言來實現它。

2.2 問題分析

從上面這個圖中我們可以找出所有的狀態:沒有一塊錢、有一塊錢、售出糖果盒糖果告罄。也就是上圖中的圓圈部分。為了提高程序的擴展性和維護性,我們采用狀態模式來設計代碼。將四個狀態映射為對應的四個類。

我們需要做的事情如下:

  • 首先定義一個 State 接口。在這個接口內,糖果機的每個動作都有一個對應的方法。
  • 然后為機器中的每個狀態實現狀態類。這些類將負責在對應的狀態下為糖果機工作。
  • 將動作委托到狀態類。
  • 2.3 狀態模式設計類圖

    2.4 代碼實現

    上下文糖果機 CandyMachine 類

    package com.jas.state;/*** 糖果機類* @author Jas* @create 2018-01-31 10:35**/ public class CandyMachine {State noCoinState;State hasCoinState;State soldState;State soldOutState;State state = soldOutState;/** 剛開始糖果機中是沒有糖果的,所以 count 為 0 */int count = 0; /*** 通過構造函數實例化所有狀態對象* @param numberCandys 初始化糖果機中的糖果數量*/public CandyMachine(int numberCandys){noCoinState = new NoCoinState(this);hasCoinState = new HasCoinState(this);soldState = new SoldState(this);soldOutState = new SoldOutState(this);this.count = numberCandys;//如果超過 0 顆糖果,就把狀態設為 noCoinStateif(numberCandys > 0){state = noCoinState;}}public void insertCoin(){state.insertCoin();}public void ejectCoin(){state.ejectCoin();}public void turnCrank(){state.turnCrank();state.dispense();}/*** 該方法用于釋放糖果,并將 count 的數量減一*/void releaseBall(){System.out.println("糖果機釋放一個糖果 ...");if (count != 0){count --;}}public State getNoCoinState() {return noCoinState;}public State getHasCoinState() {return hasCoinState;}public State getSoldState() {return soldState;}public State getSoldOutState() {return soldOutState;}public int getCount() {return count;}public void setState(State state){this.state = state;} }

    抽象狀態 State 接口

    package com.jas.state;/*** 所有的狀態接口* @author Jas* @create 2018-01-31 10:28**/ public interface State {/** 投入一個硬幣 */void insertCoin();/** 彈出硬幣 */void ejectCoin();/** 轉動曲柄 */void turnCrank();/** 糖果分發或告罄 */void dispense(); }

    具體狀態 NoCoinState 類

    package com.jas.state;/*** @author Jas* @create 2018-01-31 10:30**/ public class NoCoinState implements State {CandyMachine candyMachine;public NoCoinState(CandyMachine candyMachine){this.candyMachine = candyMachine;}/*** 投入硬幣后,將糖果機置為有一個硬幣的狀態*/@Overridepublic void insertCoin() {System.out.println("你投入了一個硬幣!");candyMachine.setState(candyMachine.getHasCoinState());}@Overridepublic void ejectCoin() {System.out.println("你還沒有投入一個硬幣!");}@Overridepublic void turnCrank() {System.out.println("即使你轉動了曲柄,但是不會出糖果,因為你沒有投入硬幣!");}@Overridepublic void dispense() {System.out.println("你需要先投入一個硬幣!");} }

    具體狀態 HasCoinState 類

    package com.jas.state;/*** @author Jas* @create 2018-01-31 10:39**/ public class HasCoinState implements State {CandyMachine candyMachine;public HasCoinState(CandyMachine candyMachine){this.candyMachine = candyMachine;}@Overridepublic void insertCoin() {System.out.println("你已經投入了一個硬幣,不能再投入硬幣了!");}/*** 在糖果機有一個硬幣的時候,你可以申請退回你的硬幣,并改變糖果機的狀態*/@Overridepublic void ejectCoin() {System.out.println("您的硬幣已退回!");candyMachine.setState(candyMachine.getNoCoinState());}/*** 糖果機有硬幣的時候,你可以轉動曲柄,從而獲得糖果,并改變糖果機的狀態*/@Overridepublic void turnCrank() {System.out.println("你轉動了曲柄,請稍等 ...");candyMachine.setState(candyMachine.getSoldState());}@Overridepublic void dispense() {System.out.println("現在還沒有糖果發放!");} }

    具體狀態 SoldState 類

    package com.jas.state;/*** @author Jas* @create 2018-01-31 10:40**/ public class SoldState implements State {CandyMachine candyMachine;public SoldState(CandyMachine candyMachine){this.candyMachine = candyMachine;}@Overridepublic void insertCoin() {System.out.println("現在不能投入硬幣了,請稍等,馬上為您發放一個糖果!");}@Overridepublic void ejectCoin() {System.out.println("您已經轉動了曲柄,現在不能再退回硬幣了!");}@Overridepublic void turnCrank() {System.out.println("您已經轉動了曲柄一次,多余的轉動是無效的!");}/*** 分發糖果,并根據糖果機中的糖果數量,改變糖果機的狀態*/@Overridepublic void dispense() {candyMachine.releaseBall();//如果糖果機中有糖果,將糖果機置為初始沒有硬幣的狀態if(candyMachine.getCount() > 0){candyMachine.setState(candyMachine.getNoCoinState());}else {System.out.println("糖果已經售賣完了,請改天再來!");candyMachine.setState(candyMachine.getSoldOutState());}} }

    具體狀態 SoldOutState 類

    package com.jas.state;/*** @author Jas* @create 2018-01-31 10:41**/ public class SoldOutState implements State {CandyMachine candyMachine;public SoldOutState(CandyMachine candyMachine){this.candyMachine = candyMachine;}@Overridepublic void insertCoin() {System.out.println("請不要再投入硬幣了,糖果已經賣完了!");}@Overridepublic void ejectCoin() {System.out.println("您沒有投入硬幣,所以現在不能彈出硬幣!");}@Overridepublic void turnCrank() {System.out.println("即使你轉動了曲柄,但還是不會出糖果,因為已經沒有糖果了!");}@Overridepublic void dispense() {System.out.println("糖果已經賣完了,沒有糖果用于發放了!");} }

    測試類

    package com.jas.state;/*** @author Jas* @create 2018-01-31 11:04**/ public class CansyMachineTestDrive {public static void main(String[] args) {//初始化糖果機中的糖果數量為 1 個CandyMachine candyMachine = new CandyMachine(1); candyMachine.insertCoin();candyMachine.ejectCoin();System.out.println("======================");candyMachine.insertCoin();candyMachine.turnCrank();System.out.println("======================");candyMachine.insertCoin();candyMachine.turnCrank();} }/*** 輸出* 你投入了一個硬幣!* 您的硬幣已退回!* ======================* 你投入了一個硬幣!* 你轉動了曲柄,請稍等 ...* 糖果機釋放一個糖果 ...* 糖果已經售賣完了,請改天再來!* ======================* 請不要再投入硬幣了,糖果已經賣完了!* 即使你轉動了曲柄,但還是不會出糖果,因為已經沒有糖果了!* 糖果已經賣完了,沒有糖果用于發放了!*/

    2.5 問題總結

    在上面這個例子中,客戶并不直接與具體狀態類直接交互,而是通過糖果機類向狀態類發出請求,還有要注意的是,客戶并不會直接改變糖果機的狀態。了解狀態的是糖果機類,客戶并不了解,所以客戶不會直接與狀態類交互。在糖果機類中有一個狀態實例,用這個實例來完成狀態之間不同的切換。

    三、 狀態模式總結

    3.1 狀態模式的優缺點

    優點

    • 封裝了轉換規則。
    • 枚舉可能的狀態,在枚舉狀態之前需要確定狀態種類。
    • 將所有與某個狀態有關的行為放到一個類中,并且可以方便地增加新的狀態,只需要改變對象狀態即可改變對象的行為。
    • 允許狀態轉換邏輯與狀態對象合成一體,而不是某一個巨大的條件語句塊。
    • 可以讓多個環境對象共享一個狀態對象,從而減少系統中對象的個數。

    缺點

  • 狀態模式的使用必然會增加系統類和對象的個數。
  • 狀態模式的結構與實現都較為復雜,如果使用不當將導致程序結構和代碼的混亂。
  • 狀態模式對”開閉原則”的支持并不太好,對于可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的源代碼,否則無法切換到新增狀態,而且修改某個狀態類的行為也需修改對應類的源代碼。
  • 3.2 狀態模式知識總結

    • 狀態模式允許一個對象基于內部的狀態而擁有不同的行為。
    • 狀態模式用類來表示狀態。
    • 上下文 (Context) 會將行為委托給當前的狀態對象。
    • 狀態模式和策略模式雖然有相同的類圖,但是它們的意圖是不一樣的。
    • 狀態模式允許上下文隨著狀態的改變而改變行為。
    • 使用狀態模式通常會導致類的數量大量增加。
    • 狀態類可以被多個上下文 (Context) 實例共享。

    PS:點擊了解更多設計模式 http://blog.csdn.net/codejas/article/details/79236013

    參考文獻

    《Head First 設計模式》
    http://www.runoob.com/design-pattern/state-pattern.html

    總結

    以上是生活随笔為你收集整理的Java 设计模式之状态模式的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。