Java设计模式之行为型:状态模式
背景:
????????介紹狀態模式前,我們先看這樣一個實例:公司力排萬難終于獲得某個酒店的系統開發項目,并且最終落到了你的頭上。下圖是他們系統的主要工作:
????????當第一眼看到這個系統時你就看出這是一個狀態圖,每個框都代表了房間的狀態,箭頭表示房間狀態的轉換。分析如下:房間有三個狀態:空閑、已預訂、已入住,狀態與狀態之間可以根據客戶的動作來進行轉換,定義每個狀態的值。
public static final int FREEMTIME_STATE = 0; //空閑狀態public static final int BOOKED_STATE = 1; //已預訂狀態public static final int CHECKIN_STATE = 2; //入住狀態int state = FREEMTIME_STATE; //初始狀態????????通過客戶的動作將每個狀態整合起來,實現這個功能最簡單的方式肯定是 if…else 啦!所以這里我們就通過動作將所有的狀態全面整合起來。分析得這里有四個動作:預訂、入住、退訂、退房。如下:
/*** @desc 預訂*/public void bookRoom(){if(state == FREEMTIME_STATE){ //空閑可預訂if(count > 0){System.out.println("空閑房間,完成預訂...");state = BOOKED_STATE; //改變狀態:已預訂count --;//房間預訂完了,提示客戶沒有房源了if(count == 0){System.out.println("不好意思,房間已經預訂完,歡迎您下次光臨...");}}else{System.out.println("不好意思,已經沒有房間了....");}}else if(state == BOOKED_STATE){System.out.println("該房間已經被預訂了...");}else if(state == CHECKIN_STATE){System.out.println("該房間已經有人入住了...");}}/*** @desc 入住*/public void checkInRoom(){if(state == FREEMTIME_STATE){if(count > 0){System.out.println("空閑房間,入住...");state = CHECKIN_STATE; //改變狀態:已預訂count --;//房間預訂完了,提示客戶沒有房源了if(count == 0){System.out.println("不好意思,房間已經預訂完,歡迎您下次光臨...");}}else{System.out.println("不好意思,已經沒有房間了....");}}else if(state == BOOKED_STATE){if("如果該房間是您預訂的"){System.out.println("入住....");state = CHECKIN_STATE;}else{System.out.println("您沒有預訂該房間,請先預訂...");}}else if(state == CHECKIN_STATE){System.out.println("該房間已經入住了...");}}/*** @desc 退訂*/public void unsubscribeRoom(){if(state == FREEMTIME_STATE){}else if(state == CHECKIN_STATE){}else if(state == BOOKED_STATE){System.out.println("已退訂房間...");state = FREEMTIME_STATE;count ++;}}/*** @desc 退房*/public void checkOutRoom(){if(state == FREEMTIME_STATE){}else if(state == BOOKED_STATE){}else if(state == CHECKIN_STATE){System.out.println("已退房..");state = FREEMTIME_STATE;count++;}}????????正當你完成這個 “復雜” 的 if..else 時,客戶增加需求說需要將某些房間保留下來以作為備用(standbyState),于是悲劇了,因為你發現要在所有的操作里都要判斷該房間是否為備用房間。當你老大經過你身邊的時候發現你正在糾結怎么改的時候,你老大就問你為什么不換一個角度思考以狀態為原子來改變它的行為,而不是通過行為來改變狀態呢?于是你就學到了狀態模式。
一、什么是狀態模式:
? ? ? ? 狀態模式,就是允許對象在內部狀態發生改變時改變它的行為,對象看起來就好像修改了它的類,也就是說以狀態為原子來改變它的行為,而不是通過行為來改變狀態。
? ? ? ? 當對象的行為取決于它的屬性時,我們稱這些屬性為狀態,那該對象就稱為狀態對象。對于狀態對象而言,它的行為依賴于它的狀態,比如要預訂房間,只有當該房間空閑時才能預訂,想入住該房間也只有當你預訂了該房間或者該房間為空閑時。對于這樣的一個對象,當它的外部事件產生互動的時候,其內部狀態就會發生變化,從而使得他的行為也隨之發生變化。
????????
二、UML結構圖:
- Context:環境類,可以包括一些內部狀態
- State:抽象狀態類,定義了所有具體狀態的共同接口,任何狀態都需要實現這個接口,從而實現狀態間的互相轉換
- ConcreteState:具體狀態類,處理來自 Context 的請求,每一個 ConcreteState 都提供了它對自己請求的實現,所以,當 Context 改變狀態時行為也會跟著改變
從上面的UML結構圖我們可以看出狀態模式的優點在于:
(1)封裝了轉換規則,允許狀態轉換邏輯與狀態對象合成一體,而不是某一個巨大的條件語句塊
(2)將所有與狀態有關的行為放到一個類中,可以方便地增加新的狀態,只需要改變對象狀態即可改變對象的行為。?
但是狀態模式的缺點在于:
(1)需要在枚舉狀態之前需要確定狀態種類
(2)會導致增加系統類和對象的個數。
(3)對 “開閉原則” 的支持并不友好,新增狀態類需要修改那些負責狀態轉換的源代碼,否則無法切換到新增狀態;而且修改某個狀態類的行為也需修改對應類的源代碼。
所以狀態模式適用于:代碼中包含大量與對象狀態有關的條件語句,以及對象的行為依賴于它的狀態,并且可以根據它的狀態改變而改變它的相關行為。
策略模式和狀態模式比較:策略模式和狀態模式的結構幾乎完全一致,但是它們的目的和本質完全不一樣。策略模式是圍繞可以互換的算法來創建業務的,而狀態模式是通過改變對象內部的狀態來幫助對象控制自己行為的。前者行為是彼此獨立、可以相互替換的,后者行為是不可以相互替換的。
三、代碼實現:
以前面的酒店的案例進行代碼實現,對于該實例的UML圖如下:
首先是狀態接口:State
public interface State {/*** @desc 預訂房間*/public void bookRoom();/*** @desc 退訂房間*/public void unsubscribeRoom();/*** @desc 入住*/public void checkInRoom();/*** @desc 退房*/public void checkOutRoom();}然后是房間類:
public class Room {/** 房間的三個狀態*/State freeTimeState; //空閑狀態State checkInState; //入住狀態State bookedState; //預訂狀態State state ; public Room(){freeTimeState = new FreeTimeState(this);checkInState = new CheckInState(this);bookedState = new BookedState(this);state = freeTimeState ; //初始狀態為空閑}/*** @desc 預訂房間*/public void bookRoom(){state.bookRoom();}/*** @desc 退訂房間*/public void unsubscribeRoom(){state.unsubscribeRoom();}/*** @desc 入住*/public void checkInRoom(){state.checkInRoom();}/*** @desc 退房*/public void checkOutRoom(){state.checkOutRoom();}public String toString(){return "該房間的狀態是:"+getState().getClass().getName();}/** getter和setter方法*/public State getFreeTimeState() {return freeTimeState;}public void setFreeTimeState(State freeTimeState) {this.freeTimeState = freeTimeState;}public State getCheckInState() {return checkInState;}public void setCheckInState(State checkInState) {this.checkInState = checkInState;}public State getBookedState() {return bookedState;}public void setBookedState(State bookedState) {this.bookedState = bookedState;}public State getState() {return state;}public void setState(State state) {this.state = state;} }??然后是3個狀態類,這個三個狀態分別對于這:空閑、預訂、入住。其中空閑可以完成預訂和入住兩個動作,預訂可以完成入住和退訂兩個動作,入住可以退房。
/** * @Description: 空閑狀態只能預訂和入住*/ public class FreeTimeState implements State {Room hotelManagement;public FreeTimeState(Room hotelManagement){this.hotelManagement = hotelManagement;}public void bookRoom() {System.out.println("您已經成功預訂了...");hotelManagement.setState(hotelManagement.getBookedState()); //狀態變成已經預訂}public void checkInRoom() {System.out.println("您已經成功入住了...");hotelManagement.setState(hotelManagement.getCheckInState()); //狀態變成已經入住}public void checkOutRoom() {//不需要做操作}public void unsubscribeRoom() {//不需要做操作} } /** * @Description: 入住狀態房間只能退房*/ public class BookedState implements State {Room hotelManagement;public BookedState(Room hotelManagement) {this.hotelManagement = hotelManagement;}public void bookRoom() {System.out.println("該房間已近給預定了...");}public void checkInRoom() {System.out.println("入住成功..."); hotelManagement.setState(hotelManagement.getCheckInState()); //狀態變成入住}public void checkOutRoom() {//不需要做操作}public void unsubscribeRoom() {System.out.println("退訂成功,歡迎下次光臨...");hotelManagement.setState(hotelManagement.getFreeTimeState()); //變成空閑狀態} } /** * @Description: 入住可以退房*/ public class CheckInState implements State {Room hotelManagement;public CheckInState(Room hotelManagement) {this.hotelManagement = hotelManagement;}public void bookRoom() {System.out.println("該房間已經入住了...");}public void checkInRoom() {System.out.println("該房間已經入住了...");}public void checkOutRoom() {System.out.println("退房成功....");hotelManagement.setState(hotelManagement.getFreeTimeState()); //狀態變成空閑}public void unsubscribeRoom() {//不需要做操作} }最后是測試類:
public class Test {public static void main(String[] args) {//有3間房Room[] rooms = new Room[2];//初始化for(int i = 0 ; i < rooms.length ; i++){rooms[i] = new Room();}//第一間房rooms[0].bookRoom(); //預訂rooms[0].checkInRoom(); //入住rooms[0].bookRoom(); //預訂System.out.println(rooms[0]);System.out.println("---------------------------");//第二間房rooms[1].checkInRoom();rooms[1].bookRoom();rooms[1].checkOutRoom();rooms[1].bookRoom();System.out.println(rooms[1]);} }運行結果:
?設計模式系列文章:
Java設計模式之創建型:工廠模式詳解(簡單工廠+工廠方法+抽象工廠)
Java設計模式之創建型:建造者模式
Java設計模式之創建型:單例模式
Java設計模式之創建型:原型模式
Java設計模式之結構型:適配器模式
Java設計模式之結構型:裝飾器模式
Java設計模式之結構型:代理模式
Java設計模式之結構型:橋接模式
Java設計模式之結構型:外觀模式
Java設計模式之結構型:組合模式
Java設計模式之結構型:享元模式
Java設計模式之行為型:策略模式
Java設計模式之行為型:模板方法模式
Java設計模式之行為型:責任鏈模式
Java設計模式之行為型:觀察者模式
Java設計模式之行為型:訪問者模式
Java設計模式之行為型:中介者模式
Java設計模式之行為型:命令模式
Java設計模式之行為型:狀態模式
Java設計模式之行為型:備忘錄模式
Java設計模式之行為型:迭代器模式
Java設計模式之行為型:解釋器模式
原博客鏈接:設計模式讀書筆記-----狀態模式_chenssy 的技術博客-CSDN博客
總結
以上是生活随笔為你收集整理的Java设计模式之行为型:状态模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java设计模式之行为型:备忘录模式
- 下一篇: Java设计模式之行为型:访问者模式