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