1. 程式人生 > >《大話設計模式》——讀後感 (10)無盡加班何時休?——狀態模式

《大話設計模式》——讀後感 (10)無盡加班何時休?——狀態模式

mce style ram 依賴 sta 回調 shm 有一點 div

原文定義:

   狀態模式:當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變其類【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 {

    @Override
    public 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 {

    @Override
    public 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 {
    
    @Override
    public 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 {

    @Override
    public 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

《大話設計模式》——讀後感 (10)無盡加班何時休?——狀態模式