欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設(shè)計(jì)模式之java狀態(tài)模式詳解

 更新時(shí)間:2021年09月15日 09:29:22   作者:大忽悠愛忽悠  
這篇文章主要介紹了Java設(shè)計(jì)模式之狀態(tài)模式定義與用法,結(jié)合具體實(shí)例形式詳細(xì)分析了Java狀態(tài)模式的概念、原理、定義及相關(guān)操作技巧,需要的朋友可以參考下

狀態(tài)模式的結(jié)構(gòu)

用一句話來表述,狀態(tài)模式把所研究的對(duì)象的行為包裝在不同的狀態(tài)對(duì)象里,每一個(gè)狀態(tài)對(duì)象都屬于一個(gè)抽象狀態(tài)類的一個(gè)子類。狀態(tài)模式的意圖是讓一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變的時(shí)候,其行為也隨之改變。狀態(tài)模式的示意性類圖如下所示:

在這里插入圖片描述

狀態(tài)模式的角色

  •  環(huán)境(Context)角色,也成上下文:定義客戶端所感興趣的接口,并且保留一個(gè)具體狀態(tài)類的實(shí)例。這個(gè)具體狀態(tài)類的實(shí)例給出此環(huán)境對(duì)象的現(xiàn)有狀態(tài)。
  •  抽象狀態(tài)(State)角色:定義一個(gè)接口,用以封裝環(huán)境(Context)對(duì)象的一個(gè)特定的狀態(tài)所對(duì)應(yīng)的行為。
  •  具體狀態(tài)(ConcreteState)角色:每一個(gè)具體狀態(tài)類都實(shí)現(xiàn)了環(huán)境(Context)的一個(gè)狀態(tài)所對(duì)應(yīng)的行為。

 示例代碼

環(huán)境角色類

public class Context {
    //持有一個(gè)State類型的對(duì)象實(shí)例
    private State state;

    public void setState(State state) {
        this.state = state;
    }
    /**
     * 用戶感興趣的接口方法
     */
    public void request(String sampleParameter) {
        //轉(zhuǎn)調(diào)state來處理
        state.handle(sampleParameter);
    }
}

抽象狀態(tài)類

public interface State {
    /**
     * 狀態(tài)對(duì)應(yīng)的處理
     */
    public void handle(String sampleParameter);
}

具體狀態(tài)類

public class ConcreteStateA implements State {

    @Override
    public void handle(String sampleParameter) {
        
        System.out.println("ConcreteStateA handle :" + sampleParameter);
    }

}
public class ConcreteStateB implements State {

    @Override
    public void handle(String sampleParameter) {
        
        System.out.println("ConcreteStateB handle :" + sampleParameter);
    }

}

客戶端類

public class Client {

    public static void main(String[] args){
        //創(chuàng)建狀態(tài)
        State state = new ConcreteStateB();
        //創(chuàng)建環(huán)境
        Context context = new Context();
        //將狀態(tài)設(shè)置到環(huán)境中
        context.setState(state);
        //請(qǐng)求
        context.request("test");
    }
}

從上面可以看出,環(huán)境類Context的行為request()是委派給某一個(gè)具體狀態(tài)類的。通過使用多態(tài)性原則,可以動(dòng)態(tài)改變環(huán)境類Context的屬性State的內(nèi)容,使其從指向一個(gè)具體狀態(tài)類變換到指向另一個(gè)具體狀態(tài)類,從而使環(huán)境類的行為request()由不同的具體狀態(tài)類來執(zhí)行。

適用場(chǎng)景

(1)對(duì)象的行為依賴于它的狀態(tài),并且可以在運(yùn)行時(shí)根據(jù)狀態(tài)改變行為。

(2) 代碼中包含大量與對(duì)象狀態(tài)有關(guān)的條件語句:一個(gè)操作中含有龐大的多分支的條件(if else(或switch case)語句,且這些分支依賴于該對(duì)象的狀態(tài)。這個(gè)狀態(tài)通常用一個(gè)或多個(gè)枚舉常量表示。通常 , 有多個(gè)操作包含這一相同的條件結(jié)構(gòu)。 State模式將每一個(gè)條件分支放入一個(gè)獨(dú)立的類中。這使得你可以根據(jù)對(duì)象自身的情況將對(duì)象的狀態(tài)作為一個(gè)對(duì)象,這一對(duì)象可以不依賴于其他對(duì)象而獨(dú)立變化。

投票案例

考慮一個(gè)在線投票系統(tǒng)的應(yīng)用,要實(shí)現(xiàn)控制同一個(gè)用戶只能投一票,如果一個(gè)用戶反復(fù)投票,而且投票次數(shù)超過5次,則判定為惡意刷票,要取消該用戶投票的資格,當(dāng)然同時(shí)也要取消他所投的票;如果一個(gè)用戶的投票次數(shù)超過8次,將進(jìn)入黑名單,禁止再登錄和使用系統(tǒng)。

要使用狀態(tài)模式實(shí)現(xiàn),首先需要把投票過程的各種狀態(tài)定義出來,根據(jù)以上描述大致分為四種狀態(tài):正常投票、反復(fù)投票、惡意刷票、進(jìn)入黑名單。然后創(chuàng)建一個(gè)投票管理對(duì)象(相當(dāng)于Context)。

系統(tǒng)的結(jié)構(gòu)圖如下所示:

在這里插入圖片描述

抽象狀態(tài)類

//抽象狀態(tài)類
public interface VoteState
{
    /**
     * 處理狀態(tài)對(duì)應(yīng)的行為
     * @param user    投票人
     * @param voteItem    投票項(xiàng)
     * @param voteManager    投票上下文,用來在實(shí)現(xiàn)狀態(tài)對(duì)應(yīng)的功能處理的時(shí)候,
     *                         可以回調(diào)上下文的數(shù)據(jù)
     */
    public void vote(String user,String voteItem,VoteManager voteManager);
}

具體狀態(tài)類——正常投票

//具體狀態(tài)類---正常投票
public class NormalVoteState implements VoteState
{

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

具體狀態(tài)類–重復(fù)投票

//具體狀態(tài)類--重復(fù)投票
public class RepeatVoteState implements VoteState
{

    @Override
    public void vote(String user, String voteItem, VoteManager voteManager) {
            //重復(fù)投票,暫時(shí)不做處理
            System.out.println("請(qǐng)不要重復(fù)投票");
    }
}

具體狀態(tài)類—惡意投票

//惡意刷票
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("你有惡意刷屏行為,取消投票資格");
    }
}

具體狀態(tài)類–黑名單

//黑名單
public class BlackVoteState implements VoteState
{
    @Override
    public void vote(String user, String voteItem, VoteManager voteManager) {
//記錄黑名單中,禁止登錄系統(tǒng)
        System.out.println("進(jìn)入黑名單,將禁止登錄和使用本系統(tǒng)");
    }
}

環(huán)境類

//環(huán)境類
public class VoteManager
{
    //維護(hù)一個(gè)抽象狀態(tài)對(duì)象
    private VoteState state;
    //記錄用戶投票的結(jié)果,Map<String,String>對(duì)應(yīng)Map<用戶名稱,投票的選項(xiàng)>
    private Map<String,String> mapVote = new HashMap<String,String>();
    //記錄用戶投票次數(shù),Map<String,Integer>對(duì)應(yīng)Map<用戶名稱,投票的次數(shù)>
    private Map<String,Integer> mapVoteCount = new HashMap<String,Integer>();
    /**
     * 獲取用戶投票結(jié)果的Map
     */
    public Map<String, String> getMapVote() {
        return mapVote;
    }
    /**
     * 投票
     * @param user    投票人
     * @param voteItem    投票的選項(xiàng)
     */
    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);
        //2.判斷該用戶的投票類型,就相當(dāng)于判斷對(duì)應(yīng)的狀態(tài)
        //到底是正常投票、重復(fù)投票、惡意投票還是上黑名單的狀態(tài)
        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();
        }
        //然后轉(zhuǎn)調(diào)狀態(tài)對(duì)象來進(jìn)行相應(yīng)的操作
        state.vote(user, voteItem, this);
    }
}

客戶端測(cè)試

public class Client
{
    public static void main(String[] args) {

        VoteManager vm = new VoteManager();
        for(int i=0;i<9;i++){
            vm.vote("u1","A");
        }
    }
}

在這里插入圖片描述

從上面的示例可以看出,狀態(tài)的轉(zhuǎn)換基本上都是內(nèi)部行為,主要在狀態(tài)模式內(nèi)部來維護(hù)。比如對(duì)于投票的人員,任何時(shí)候他的操作都是投票,但是投票管理對(duì)象的處理卻不一定一樣,會(huì)根據(jù)投票的次數(shù)來判斷狀態(tài),然后根據(jù)狀態(tài)去選擇不同的處理。

認(rèn)識(shí)狀態(tài)模式

狀態(tài)和行為

  •  所謂對(duì)象的狀態(tài),通常指的就是對(duì)象實(shí)例的屬性的值;而行為指的就是對(duì)象的功能,再具體點(diǎn)說,行為大多可以對(duì)應(yīng)到方法上。
  •  狀態(tài)模式的功能就是分離狀態(tài)的行為,通過維護(hù)狀態(tài)的變化,來調(diào)用不同狀態(tài)對(duì)應(yīng)的不同功能。也就是說,狀態(tài)和行為是相關(guān)聯(lián)的,它們的關(guān)系可以描述為:狀態(tài)決定行為。
  •  由于狀態(tài)是在運(yùn)行期被改變的,因此行為也會(huì)在運(yùn)行期根據(jù)狀態(tài)的改變而改變。

行為的平行性

注意平行線而不是平等性。所謂平行性指的是各個(gè)狀態(tài)的行為所處的層次是一樣的,相互獨(dú)立的、沒有關(guān)聯(lián)的,是根據(jù)不同的狀態(tài)來決定到底走平行線的哪一條。行為是不同的,當(dāng)然對(duì)應(yīng)的實(shí)現(xiàn)也是不同的,相互之間是不可替換的。

在這里插入圖片描述

而平等性強(qiáng)調(diào)的是可替換性,大家是同一行為的不同描述或?qū)崿F(xiàn),因此在同一個(gè)行為發(fā)生的時(shí)候,可以根據(jù)條件挑選任意一個(gè)實(shí)現(xiàn)來進(jìn)行相應(yīng)的處理。

在這里插入圖片描述

大家可能會(huì)發(fā)現(xiàn)狀態(tài)模式的結(jié)構(gòu)和策略模式的結(jié)構(gòu)完全一樣,但是,它們的目的、實(shí)現(xiàn)、本質(zhì)卻是完全不一樣的。還有行為之間的特性也是狀態(tài)模式和策略模式一個(gè)很重要的區(qū)別,狀態(tài)模式的行為是平行性的,不可相互替換的;而策略模式的行為是平等性的,是可以相互替換的。

環(huán)境和狀態(tài)處理對(duì)象

  •  在狀態(tài)模式中,環(huán)境(Context)是持有狀態(tài)的對(duì)象,但是環(huán)境(Context)自身并不處理跟狀態(tài)相關(guān)的行為,而是把處理狀態(tài)的功能委托給了狀態(tài)對(duì)應(yīng)的狀態(tài)處理類來處理。
  •  在具體的狀態(tài)處理類中經(jīng)常需要獲取環(huán)境(Context)自身的數(shù)據(jù),甚至在必要的時(shí)候會(huì)回調(diào)環(huán)境(Context)的方法,因此,通常將環(huán)境(Context)自身當(dāng)作一個(gè)參數(shù)傳遞給具體的狀態(tài)處理類。
  •  客戶端一般只和環(huán)境(Context)交互。客戶端可以用狀態(tài)對(duì)象來配置一個(gè)環(huán)境(Context),一旦配置完畢,就不再需要和狀態(tài)對(duì)象打交道了??蛻舳送ǔ2回?fù)責(zé)運(yùn)行期間狀態(tài)的維護(hù),也不負(fù)責(zé)決定后續(xù)到底使用哪一個(gè)具體的狀態(tài)處理對(duì)象。

狀態(tài)模式優(yōu)點(diǎn)

  •  每個(gè)狀態(tài)都是一個(gè)子類,只要增加狀態(tài)就要增加子類,修改狀態(tài),只修改一個(gè)子類即可。
  •  結(jié)構(gòu)清晰,避免了過多的switch…case或者if…else語句的使用,避免了程序的復(fù)雜性,提高可維護(hù)性。
  •  State對(duì)象可被共享如果State對(duì)象沒有實(shí)例變量—即它們表示的狀態(tài)完全以它們的類型來編碼—那么各Context對(duì)象可以共享一個(gè)State對(duì)象。當(dāng)狀態(tài)以這種方式被共享時(shí),它們必然是沒有內(nèi)部狀態(tài), 只有行為的輕量級(jí)對(duì)象。

狀態(tài)模式的缺點(diǎn)

  •  狀態(tài)模式的使用必然會(huì)增加系統(tǒng)類和對(duì)象的個(gè)數(shù)。
  •  狀態(tài)模式的結(jié)構(gòu)與實(shí)現(xiàn)都較為復(fù)雜,如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂。

狀態(tài)模式和策略模式對(duì)比

相同之處:

  •  在狀態(tài)模式和策略模式中,Context對(duì)象對(duì)修改是關(guān)閉的,添加新的狀態(tài)或策略,都不需要修改Context。
  •  正如狀態(tài)模式中的Context會(huì)有初始狀態(tài)一樣,策略模式同樣有默認(rèn)策略。
  •  狀態(tài)模式以不同的狀態(tài)封裝不同的行為,而策略模式以不同的策略封裝不同的行為。
  •  它們都依賴子類去實(shí)現(xiàn)相關(guān)行為

不同之處:

最根本的差異在于策略模式是在求解同一個(gè)問題的多種解法,這些不同解法之間毫無關(guān)聯(lián);狀態(tài)模式則不同,狀態(tài)模式要求各個(gè)狀態(tài)之間有所關(guān)聯(lián),以便實(shí)現(xiàn)狀態(tài)轉(zhuǎn)移。

參考文章

《JAVA與模式》之狀態(tài)模式

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • MybatisPlus 連表查詢、邏輯刪除功能實(shí)現(xiàn)(多租戶)

    MybatisPlus 連表查詢、邏輯刪除功能實(shí)現(xiàn)(多租戶)

    這篇文章主要介紹了MybatisPlus 連表查詢、邏輯刪除功能實(shí)現(xiàn)(多租戶),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • 完美解決java double數(shù)相加和相減的方案

    完美解決java double數(shù)相加和相減的方案

    這篇文章主要介紹了完美解決java double數(shù)相加和相減的方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • spring中的注入list集合

    spring中的注入list集合

    這篇文章主要介紹了spring中的注入list集合問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Spring?注入集合實(shí)現(xiàn)過程示例詳解

    Spring?注入集合實(shí)現(xiàn)過程示例詳解

    這篇文章主要為大家介紹了Spring?注入集合實(shí)現(xiàn)過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • java處理轉(zhuǎn)義字符↑ → ↓ 保存后的展示還原操作

    java處理轉(zhuǎn)義字符↑ → ↓ 保存后的展示還原操作

    這篇文章主要介紹了java處理轉(zhuǎn)義字符↑ → ↓ 保存后的展示還原操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java正則表達(dá)式判斷字符串中是否包含中文示例

    Java正則表達(dá)式判斷字符串中是否包含中文示例

    之前一個(gè)朋友問我,如何判斷字符串中是否包含中文,其實(shí)解決的方法很簡(jiǎn)單,但覺著有必要寫出給不知道的朋友們以參考,所以下面這篇文章主要介紹了利用Java正則表達(dá)式判斷字符串中是否包含中文的方法,需要的朋友可以參考。
    2017-03-03
  • Java @SentinelResource全面介紹

    Java @SentinelResource全面介紹

    在實(shí)際應(yīng)用過程中,我們可能需要限流的層面不僅限于接口??赡軐?duì)于某個(gè)方法的調(diào)用限流,對(duì)于某個(gè)外部資源的調(diào)用限流等都希望做到控制。對(duì)此,我們需要學(xué)習(xí)使用@SentinelResource注解,靈活的定義控制資源以及如何配置控制策略
    2022-08-08
  • 實(shí)例解析Java日期格式工具類DateUtil.java

    實(shí)例解析Java日期格式工具類DateUtil.java

    本文主要對(duì)Java日期格式工具類DateUtil.java進(jìn)行實(shí)例解析。具有一定的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01
  • Java?詳細(xì)講解線程的狀態(tài)及部分常用方法

    Java?詳細(xì)講解線程的狀態(tài)及部分常用方法

    在Java程序中,一個(gè)線程對(duì)象只能調(diào)用一次start()方法啟動(dòng)新線程,并在新線程中執(zhí)行run()方法。一旦run()方法執(zhí)行完畢,線程就結(jié)束了,本篇來講解Java線程的狀態(tài)以及部分常用方法
    2022-04-04
  • 解決SpringBoot webSocket 資源無法加載、tomcat啟動(dòng)報(bào)錯(cuò)的問題

    解決SpringBoot webSocket 資源無法加載、tomcat啟動(dòng)報(bào)錯(cuò)的問題

    這篇文章主要介紹了解決SpringBoot webSocket 資源無法加載、tomcat啟動(dòng)報(bào)錯(cuò)的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評(píng)論