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