【行为型模式】《大话设计模式》——读后感 (10)无尽加班何时休?——状态模式...
原文定義:
狀態(tài)模式:當(dāng)一個對象的內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變其類【DP】
?
UML結(jié)構(gòu)圖:
?
背景:
? 看到此模式,醞釀了好久才決定對狀態(tài)模式進行總結(jié)。光看原文定義,實在沒有獲取到什么有用的價值。
? ? ? ?第一眼看到狀態(tài)模式,感覺這不就是一個簡單工工廠模式嗎?但是仔細(xì)看看其他人的博客,發(fā)現(xiàn)狀態(tài)模式和簡單工廠模式還是有一定的區(qū)別的,最明顯的是Context類持有了State,這一點和簡單工廠區(qū)別很大。但是我發(fā)現(xiàn)狀態(tài)模式又和策略模式很像,或者說是太像了。同樣有抽象接口,具體實現(xiàn)類,Context上下文類, 以及Context里面也含有一個State抽象,簡直一摸一樣啊。而且網(wǎng)上其他很多人的博客在解釋狀態(tài)模式的時候,用的分明就是策略模式的例子,真的很無解!
? ? ? ?思量再三,對《大話設(shè)計模式》中對狀態(tài)模式進行反復(fù)的研究,并且上網(wǎng)找了很多的微博進行閱讀和理解,最終才有一點收獲,并且再次進行總結(jié)。
?
其實看了很多的微博以后,再次來理解定義的時候,我們還是能獲取一點有用的信息的:
狀態(tài)模式:當(dāng)一個對象的內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變其類【DP】
?
? ?1、"對象的內(nèi)在狀態(tài)":其實這和我們在策略模式中理解的具體策略,在簡單工廠中的具體算法是類似的,稱呼不同而已。
? ?2、“當(dāng)一個對象的內(nèi)在狀態(tài)改變時允許改變其行為”: 舉例說A對象內(nèi)部持有的B改變了,此時允許B改變A的具體行為操作,即狀態(tài)控制行為。
? ?
適用性?
在下面的兩種情況下均可使用State模式:
1) ? 一個對象的行為取決于它的狀態(tài), 并且它必須在運行時刻根據(jù)狀態(tài)改變它的行為。2) ? 代碼中包含大量與對象狀態(tài)有關(guān)的條件語句:一個操作中含有龐大的多分支的條件(if else(或switch case)語句,且這些分支依賴于該對象的狀態(tài)。這個狀態(tài)通常用一個或多個枚舉常量表示。通常 , 有多個操作包含這一相同的條件結(jié)構(gòu)。 State模式將每一個條件分支放入一個獨立的類中。這使得你可以根據(jù)對象自身的情況將對象的狀態(tài)作為一個對象,這一對象可以不依賴于其他對象而獨立變化。
?
?
?
下面分享我在網(wǎng)上找到的一個關(guān)于投票的優(yōu)秀案例,我對其進行改造,看起來更加的符合狀態(tài)模式定義:
考慮一個在線投票系統(tǒng)的應(yīng)用,要實現(xiàn)控制同一個用戶只能投一票,如果一個用戶反復(fù)投票,而且投票次數(shù)超過5次,則判定為惡意刷票,要取消該用戶投票的資格,當(dāng)然同時也要取消他所投的票;如果一個用戶的投票次數(shù)超過8次,將進入黑名單,禁止再登錄和使用系統(tǒng)。
要使用狀態(tài)模式實現(xiàn),首先需要把投票過程的各種狀態(tài)定義出來,根據(jù)以上描述大致分為四種狀態(tài):正常投票、反復(fù)投票、惡意刷票、進入黑名單。然后創(chuàng)建一個投票管理對象(相當(dāng)于Context)。
?
投票的抽象接口:
package com.sjmx.state;public interface VoteState {/*** 處理狀態(tài)對應(yīng)的行為* * @param user* 投票人* @param voteItem* 投票項* @param voteManager* 投票上下文,用來在實現(xiàn)狀態(tài)對應(yīng)的功能處理的時候, 可以回調(diào)上下文的數(shù)據(jù)*/public void vote(String user, String voteItem, VoteManager voteManager,int count); }?
具體狀態(tài)類——正常投票:
package com.sjmx.state;/** * 具體狀態(tài)類——正常投票*/public class NormalVoteState implements VoteState {@Overridepublic void vote(String user, String voteItem, VoteManager voteManager,int count) {// 正常投票,記錄到投票記錄中if(1 == count){voteManager.getMapVote().put(user, voteItem);System.out.println("恭喜投票成功,投票內(nèi)容為:" + voteItem);voteManager.state = new RepeatVoteState();} } }?
具體狀態(tài)類——重復(fù)投票:
package com.sjmx.state;/** * 具體狀態(tài)類——重復(fù)投票*/public class RepeatVoteState implements VoteState {@Overridepublic void vote(String user, String voteItem, VoteManager voteManager,int count) {// 重復(fù)投票,暫時不做處理if(count > 1 && count < 5){System.out.println("請不要重復(fù)投票,投票內(nèi)容為:" + voteItem);}else{voteManager.state = new SpiteVoteState();voteManager.voteByChange(user, voteItem, count);}} }?
惡意投票:
package com.sjmx.state;public class SpiteVoteState implements VoteState {@Overridepublic void vote(String user, String voteItem, VoteManager voteManager,int count) {// 惡意投票,取消用戶的投票資格,并取消投票記錄if(count >= 5 && count < 8){System.out.println("count:" + count);String str = voteManager.getMapVote().get(user);if (str != null) {voteManager.getMapVote().remove(user);}System.out.println("你有惡意刷屏行為,取消投票資格!-----投票內(nèi)容為:" + voteItem);}else{voteManager.state = new BlackVoteState();voteManager.voteByChange(user, voteItem, count);}} }?
記錄黑名單中,禁止登錄系統(tǒng):
package com.sjmx.state;public class BlackVoteState implements VoteState {@Overridepublic void vote(String user, String voteItem, VoteManager voteManager,int count) {// 記錄黑名單中,禁止登錄系統(tǒng)System.out.println("進入黑名單,將禁止登錄和使用本系統(tǒng),投票內(nèi)容為:" + voteItem);}}?
狀態(tài)管理類:
package com.sjmx.state;import java.util.HashMap; import java.util.Map;public class VoteManager {// 持有狀體處理對象public VoteState state = null;// 記錄用戶投票的結(jié)果,Map<String,String>對應(yīng)Map<用戶名稱,投票的選項>public Map<String, String> mapVote = new HashMap<String, String>();// 記錄用戶投票次數(shù),Map<String,Integer>對應(yīng)Map<用戶名稱,投票的次數(shù)>public Map<String, Integer> mapVoteCount = new HashMap<String, Integer>();public VoteManager(String user) {state = new NormalVoteState();}/*** 獲取用戶投票結(jié)果的Map*/public Map<String, String> getMapVote() {return mapVote;}/*** 投票* @param user 投票人* @param voteItem投票的選項*/public void vote(String user, String voteItem) {// 1.為該用戶增加投票次數(shù)// 從記錄中取出該用戶已有的投票次數(shù)Integer oldVoteCount = mapVoteCount.get(user);if (oldVoteCount == null) {oldVoteCount = 0;}oldVoteCount += 1;mapVoteCount.put(user, oldVoteCount);this.voteByChange(user, voteItem, oldVoteCount);}public void voteByChange(String user, String voteItem, int count){// 然后轉(zhuǎn)調(diào)狀態(tài)對象來進行相應(yīng)的操作state.vote(user, voteItem, this,count);}}?
客戶端:
package com.sjmx.state;public class Client {public static void main(String[] args) {VoteManager vm = new VoteManager("jack");for(int i=1;i<11;i++){vm.vote("u1","A"+i);}}}?
運行結(jié)果:
恭喜投票成功,投票內(nèi)容為:A1 請不要重復(fù)投票,投票內(nèi)容為:A2 請不要重復(fù)投票,投票內(nèi)容為:A3 請不要重復(fù)投票,投票內(nèi)容為:A4 count:5 你有惡意刷屏行為,取消投票資格!-----投票內(nèi)容為:A5 count:6 你有惡意刷屏行為,取消投票資格!-----投票內(nèi)容為:A6 count:7 你有惡意刷屏行為,取消投票資格!-----投票內(nèi)容為:A7 進入黑名單,將禁止登錄和使用本系統(tǒng),投票內(nèi)容為:A8 進入黑名單,將禁止登錄和使用本系統(tǒng),投票內(nèi)容為:A9 進入黑名單,將禁止登錄和使用本系統(tǒng),投票內(nèi)容為:A10?
案例2:模擬賓館預(yù)定
package com.net.sjms.state; public interface Destine {public void fixHotel(Hotel hotel, Manager manager);}?
package com.net.sjms.state; public class Free implements Destine{@Overridepublic void fixHotel(Hotel hotel, Manager manager){if(State.free.toString().equals(hotel.getState())){System.out.println("房間狀態(tài)為:" + hotel.getState() + ", 預(yù)定成功");hotel.setState(State.full.toString());}else{manager.dest = new Full();manager.desHotel();}}} package com.net.sjms.state; public class Full implements Destine {@Overridepublic void fixHotel(Hotel hotel, Manager manager){if(State.full.toString().equals(hotel.getState())){System.out.println("對不起,房間已滿,無法完成預(yù)定!");}else{manager.dest = new Free();manager.desHotel();}}}?
房間狀態(tài):
package com.net.sjms.state; public enum State {free,full } package com.net.sjms.state; public class Hotel {private String name;public String state;public String getName(){return name;}public void setName(String name){this.name = name;}public String getState(){return state;}public void setState(String state){this.state = state;}}上下文類:
package com.net.sjms.state;public class Manager {public Destine dest;public Hotel hotel;public Manager(){this.dest = new Free();this.hotel = new Hotel();this.hotel.setState(State.free.toString());}public void desHotel(){dest.fixHotel(hotel,this);} }?
客戶端:
package com.net.sjms.state; public class Client {public static void main(String[] args){final Manager manager = new Manager();//啟動另一個線程,模擬一段時間以后,房客會退房new Thread(new Runnable() {@Overridepublic void run(){while(true){try {Thread.sleep(500);manager.hotel.setState(State.free.toString());} catch (InterruptedException e) {e.printStackTrace();}}}}).start();for(int i=0; i <30; i++){try {manager.desHotel();Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}?
運行結(jié)果:
房間狀態(tài)為:free, 預(yù)定成功 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 房間狀態(tài)為:free, 預(yù)定成功 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 房間狀態(tài)為:free, 預(yù)定成功 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 房間狀態(tài)為:free, 預(yù)定成功 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 房間狀態(tài)為:free, 預(yù)定成功 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 房間狀態(tài)為:free, 預(yù)定成功 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定! 對不起,房間已滿,無法完成預(yù)定!?
轉(zhuǎn)載于:https://www.cnblogs.com/chen1-kerr/p/7093976.html
總結(jié)
以上是生活随笔為你收集整理的【行为型模式】《大话设计模式》——读后感 (10)无尽加班何时休?——状态模式...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。