設計模式 10 —— 狀態模式 設計模式 1 ——觀察者模式 設計模式 2 —— 裝飾者模式 設計模式 3 —— 迭代器和組合模式(迭代器) 設計模式 4 —— 迭代器和組合模式(組合) 設計模式 5

設計模式目錄:html

設計模式 1 ——觀察者模式java

設計模式 2 —— 裝飾者模式 設計模式

設計模式 3 —— 迭代器和組合模式(迭代器)ide

設計模式 4 —— 迭代器和組合模式(組合)post

設計模式 5 —— 工廠模式測試

設計模式 6 —— 單件模式this

設計模式 7 —— 命令模式url

設計模式 8 —— 適配器和外觀模式spa

設計模式 9 —— 模板方法模式設計

設計模式 10 —— 狀態模式

 

概述

狀態模式的結構

使用場景

認識狀態模式

參考

 

狀態模式,又稱狀態對象模式(Pattern of Objects for States),狀態模式是對象的行爲模式。

狀態模式容許一個對象在其內部狀態改變的時候改變其行爲。這個對象看上去就像是改變了它的類同樣。

狀態模式的結構

  用一句話來表述,狀態模式把所研究的對象的行爲包裝在不一樣的狀態對象裏,每個狀態對象都屬於一個抽象狀態類的一個子類。狀態模式的意圖是讓一個對象在其內部狀態改變的時候,其行爲也隨之改變。狀態模式的示意性類圖以下所示:

  狀態模式所涉及到的角色有:

  ●  環境(Context)角色,也成上下文:定義客戶端所感興趣的接口,而且保留一個具體狀態類的實例。這個具體狀態類的實例給出此環境對象的現有狀態。

  ●  抽象狀態(State)角色:定義一個接口,用以封裝環境(Context)對象的一個特定的狀態所對應的行爲。

  ●  具體狀態(ConcreteState)角色:每個具體狀態類都實現了環境(Context)的一個狀態所對應的行爲。

  源代碼

  環境角色類

 1 public class Context {
 2     // 持有一個State類型的對象實例
 3     private State state;
 4 
 5     public void setState(State state) {
 6         this.state = state;
 7     }
 8 
 9     /**
10      * 用戶感興趣的接口方法
11      */
12     public void request(String sampleParameter) {
13         // 轉調state來處理
14         state.handle(sampleParameter);
15     }
16 
17 }

 

抽象狀態類

public interface State {
     /**
     * 狀態對應的處理
     */
    public void handle(String sampleParameter);

}

 

具體狀態類

public class ConcreteStateA implements State{

    /**
     * 
     * @Description: TODO
     * @param sampleParameter
     * @author xingle
     * @data 2015-9-25 下午1:30:43
     */
    @Override
    public void handle(String sampleParameter) {
        System.out.println("具體狀態A 處理 :" + sampleParameter);
    }

}

 

public class ConcreteStateB implements State{

    /**
     * 
     * @Description: TODO
     * @param sampleParameter
     * @author xingle
     * @data 2015-9-25 下午1:31:22
     */
    @Override
    public void handle(String sampleParameter) {
        System.out.println("具體狀態B 處理 :" + sampleParameter);
    }

}

 

客戶端類

public class Client {
     public static void main(String[] args){
            //建立狀態
            State state = new ConcreteStateB();
            //建立環境
            Context context = new Context();
            //將狀態設置到環境中
            context.setState(state);
            //請求
            context.request("測試參數");
        }

}

 

結果:

 

從上面能夠看出,環境類Context的行爲request()是委派給某一個具體狀態類的。經過使用多態性原則,能夠動態改變環境類Context的屬性State的內容,使其從指向一個具體狀態類變換到指向另外一個具體狀態類,從而使環境類的行爲request()由不一樣的具體狀態類來執行。

使用場景

  考慮一個在線投票系統的應用,要實現控制同一個用戶只能投一票,若是一個用戶反覆投票,並且投票次數超過5次,則斷定爲惡意刷票,要取消該用戶投票的資格,固然同時也要取消他所投的票;若是一個用戶的投票次數超過8次,將進入黑名單,禁止再登陸和使用系統。

  要使用狀態模式實現,首先須要把投票過程的各類狀態定義出來,根據以上描述大體分爲四種狀態:正常投票、反覆投票、惡意刷票、進入黑名單。而後建立一個投票管理對象(至關於Context)。

  系統的結構圖以下所示:

  

  源代碼

  抽象狀態類

public interface VoteState {
    /**
     * 處理狀態對應的行爲
     * @param user    投票人
     * @param voteItem    投票項
     * @param voteManager    投票上下文,用來在實現狀態對應的功能處理的時候,
     *                         能夠回調上下文的數據
     */
    public void vote(String user,String voteItem,VoteManager voteManager);
}

 

具體狀態類——正常投票

public class NormalVoteState implements VoteState {

    @Override
    public void vote(String user, String voteItem, VoteManager voteManager) {
        //正常投票,記錄到投票記錄中
        voteManager.getMapVote().put(user, voteItem);
        System.out.println("恭喜投票成功");
    }

}

 

具體狀態類——重複投票

public class RepeatVoteState implements VoteState {

    @Override
    public void vote(String user, String voteItem, VoteManager voteManager) {
        //重複投票,暫時不作處理
        System.out.println("請不要重複投票");
    }

}

 

具體狀態類——惡意刷票

public class SpiteVoteState implements VoteState {

    @Override
    public void vote(String user, String voteItem, VoteManager voteManager) {
        // 惡意投票,取消用戶的投票資格,並取消投票記錄
        String str = voteManager.getMapVote().get(user);
        if(str != null){
            voteManager.getMapVote().remove(user);
        }
        System.out.println("你有惡意刷屏行爲,取消投票資格");
    }

}

 

具體狀態類——黑名單

public class BlackVoteState implements VoteState {

    @Override
    public void vote(String user, String voteItem, VoteManager voteManager) {
        //記錄黑名單中,禁止登陸系統
        System.out.println("進入黑名單,將禁止登陸和使用本系統");
    }

}

 

環境類

public class VoteManager {
    //持有狀體處理對象
    private VoteState state = null;
    //記錄用戶投票的結果,Map<String,String>對應Map<用戶名稱,投票的選項>
    private Map<String,String> mapVote = new HashMap<String,String>();
    //記錄用戶投票次數,Map<String,Integer>對應Map<用戶名稱,投票的次數>
    private Map<String,Integer> mapVoteCount = new HashMap<String,Integer>();
    /**
     * 獲取用戶投票結果的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);
        //2.判斷該用戶的投票類型,就至關於判斷對應的狀態
        //究竟是正常投票、重複投票、惡意投票仍是上黑名單的狀態
        if(oldVoteCount == 1){
            state = new NormalVoteState();
        }
        else if(oldVoteCount > 1 && oldVoteCount < 5){
            state = new RepeatVoteState();
        }
        else if(oldVoteCount >= 5 && oldVoteCount <8){
            state = new SpiteVoteState();
        }
        else if(oldVoteCount > 8){
            state = new BlackVoteState();
        }
        //而後轉調狀態對象來進行相應的操做
        state.vote(user, voteItem, this);
    }
}

 

客戶端類

public class Client {

    public static void main(String[] args) {
        
        VoteManager vm = new VoteManager();
        for(int i=0;i<9;i++){
            vm.vote("u1","A");
        }
    }

}

 

運行結果以下:

從上面的示例能夠看出,狀態的轉換基本上都是內部行爲,主要在狀態模式內部來維護。好比對於投票的人員,任什麼時候候他的操做都是投票,可是投票管理對象的處理卻不必定同樣,會根據投票的次數來判斷狀態,而後根據狀態去選擇不一樣的處理。

認識狀態模式

  ●  狀態和行爲

  所謂對象的狀態,一般指的就是對象實例的屬性的值;而行爲指的就是對象的功能,再具體點說,行爲大多能夠對應到方法上。

  狀態模式的功能就是分離狀態的行爲,經過維護狀態的變化,來調用不一樣狀態對應的不一樣功能。也就是說,狀態和行爲是相關聯的,它們的關係能夠描述爲:狀態決定行爲

  因爲狀態是在運行期被改變的,所以行爲也會在運行期根據狀態的改變而改變。

  ●  行爲的平行性

  注意平行線而不是平等性。所謂平行性指的是各個狀態的行爲所處的層次是同樣的,相互獨立的、沒有關聯的,是根據不一樣的狀態來決定到底走平行線的哪一條。行爲是不一樣的,固然對應的實現也是不一樣的,相互之間是不可替換的。

  

  而平等性強調的是可替換性,你們是同一行爲的不一樣描述或實現,所以在同一個行爲發生的時候,能夠根據條件挑選任意一個實現來進行相應的處理。

  

  你們可能會發現狀態模式的結構和策略模式的結構徹底同樣,可是,它們的目的、實現、本質倒是徹底不同的。還有行爲之間的特性也是狀態模式和策略模式一個很重要的區別,狀態模式的行爲是平行性的,不可相互替換的;而策略模式的行爲是平等性的,是能夠相互替換的。

  ●   環境和狀態處理對象

  在狀態模式中,環境(Context)是持有狀態的對象,可是環境(Context)自身並不處理跟狀態相關的行爲,而是把處理狀態的功能委託給了狀態對應的狀態處理類來處理。

  在具體的狀態處理類中常常須要獲取環境(Context)自身的數據,甚至在必要的時候會回調環境(Context)的方法,所以,一般將環境(Context)自身看成一個參數傳遞給具體的狀態處理類。

  客戶端通常只和環境(Context)交互。客戶端能夠用狀態對象來配置一個環境(Context),一旦配置完畢,就再也不須要和狀態對象打交道了。客戶端一般不負責運行期間狀態的維護,也不負責決定後續到底使用哪個具體的狀態處理對象。

  


 

參考:

  1. 《JAVA與模式》之狀態模式
  2. Java中的狀態模式實例教程
相關文章
相關標籤/搜索