天天看點

設計模式-狀态模式

狀态模式:當一個對象的内在狀态改變時允許改變其行為,這個對象看起來像是改變了其類

通俗解釋:改變一個狀态值時,其行為發生了改變。行為也就是做了什麼。

下面一個例子:(大話設計模式的例子)

一天之中的工作狀态随着時間改變

早晨-精神百倍

中午-犯困

下午-狀态不錯

(完成工作的情況)

傍晚-下班

(沒完成工作的情況)

傍晚-沒完成工作-加班

晚上-困得要死

結合這個例子,編寫代碼

@Data
public class Work {
    private Integer hour;
    private Integer finish = 0; //預設工作沒有完成

    public void writeProgram(){
        if (hour < 12){
            System.out.println("目前時間:"+hour+"點,上午工作,精神百倍");
        }else if (hour < 13){
            System.out.println("目前時間:"+hour+"點,餓了,午飯,犯困");
        }else if (hour < 17){
            System.out.println("目前時間:"+hour+"點,下午狀态不錯,繼續努力");
        }else {
            if (finish == 1){
                System.out.println("目前時間:"+hour+"點,工作完成,下班回家");
            }else {
                if (hour < 21){
                    System.out.println("目前時間:"+hour+"點,加班,疲累至極");
                }else {
                    System.out.println("目前時間:"+hour+"點,不行了,睡着了");
                }
            }
        }
    }
}      

測試

public class WorkTest {
    public static void main(String[] args) {
        Work work = new Work();
        work.setHour(8);
        work.writeProgram();
        work.setHour(11);
        work.writeProgram();
        work.setHour(13);
        work.writeProgram();
        work.setHour(17);

        work.setFinish(1);

        work.writeProgram();
        work.setHour(18);
        work.writeProgram();
        work.setHour(20);
        work.writeProgram();
        work.setHour(22);
        work.writeProgram();
    }
}      

例子中一直都是針對hour來進行判斷,不同的時間點輸出不同的内容

但是這樣來看過多的if...else,代碼過于淩亂,後期肯定不好維護

此時這種情況就可以用狀态模式

設計模式-狀态模式

State:抽象狀态類,定義一個接口以封裝與Context的一個特定狀态的行為

ConcreteState類,具體狀态的類,每個子類實作一個狀态的行為

Context類,維護一個ConcreteState子類的執行個體,這個執行個體定義目前的狀态

按照UML類圖來改造代碼

1.建立Status類,定義每種狀态下的行為

abstract class Status {
    //為什麼要加一個Work的入參,需要 具體狀态類來負責狀态之間的轉換
    //狀态轉換也可以放到Context類來做
    public abstract void workHandle(Work work);
}      

2.建立Context類 重點是其中的Status的引用,這裡我預設了status是早晨的狀态

/**
 * Context類
 * @author wrj
 * @description
 * @Date 2021/12/13 2:03 下午
 */
@Data
public class Work {
    private Integer hour;
    private Integer finish = 0;
    private Status status = new MorningWorkStatus();


    public void writeProgram(){
        status.workHandle(this);
    }
}      

3.建立ConcreteStatus類

/**
 * 早晨的工作狀态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:08 下午
 */
public class MorningWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getHour() < 12){
            System.out.println("目前時間:"+work.getHour()+"點,上午工作,精神百倍");
        }else {
            //條件不滿足的情況下設定為中午的工作狀态
            work.setStatus(new NoonWorkStatus());
            work.writeProgram();
        }
    }
}      
/**
 * 中午工作狀态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:08 下午
 */
public class NoonWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getHour() < 12){
            System.out.println("目前時間:"+work.getHour()+"點,餓了,午飯,犯困");
        }else {
            //條件不滿足的情況下設定為下午的工作狀态
            work.setStatus(new AfterNoonWorkStatus());
            work.writeProgram();
        }
    }
}      
/**
 * 下午的工作狀态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:08 下午
 */
public class AfterNoonWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getHour() <= 17){
            System.out.println("目前時間:"+work.getHour()+"點,下午狀态不錯,繼續努力");
        }else {
            work.setStatus(new EveningWorkStatus());
            work.writeProgram();
        }
    }
}      
/**
 * 傍晚的工作狀态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:20 下午
 */
public class EveningWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getFinish() == 1){
            work.setStatus(new FinishWorkStatus());
            work.writeProgram();
        }else {
            if (work.getHour() < 20){
                System.out.println("目前時間:"+work.getHour()+"點,加班,疲累至極");
            }else {
                work.setStatus(new SleepingWorkStatus());
                work.writeProgram();
            }
        }
    }
}      
/**
 * 晚上快要睡着的工作狀态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:29 下午
 */
public class SleepingWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        System.out.println("目前時間:"+work.getHour()+"點,不行了,睡着了");
    }
}      

4.測試類

public class Test {

    public static void main(String[] args) {
        Work work = new Work();
        work.setHour(8);
        work.writeProgram();
        work.setHour(11);
        work.writeProgram();
        work.setHour(13);
        work.writeProgram();
        work.setHour(17);

        work.setFinish(0);

        work.writeProgram();
        work.setHour(18);
        work.writeProgram();
        work.setHour(20);
        work.writeProgram();
        work.setHour(22);
        work.writeProgram();
    }
}      

大話設計模式中是這麼說的:

将特定的狀态相關的行為都放入一個對象中,由于所有與狀态相關的代碼都存在于某個ConcreteState中,是以通過定義新的子類可以很容易地增加新的狀态和轉換

将每個狀态需要做的事情封裝在一個類中,不同的狀态對應不同的類,對應不同的行為。當需要增加新的狀态時,可以通過建立新的類來增加新的狀态和行為。

上面例子中的狀态轉換是在具體的類中,也可以放到Context中來做,(思路:通過判斷目前status的具體類型,然後指派為下一個階段的具體類型),然後具體的子類調用ConcreteState

使用狀态模式這樣做的好處是,假如公司決定晚上8點強制下班,那麼隻需要增加一個強制下班的子類,然後改變EveningWorkStatus的work.setStatus(new SleepingWorkStatus());将new SleepingWorkStatus()改為新建立的強制下班的子類,無須改動其他的子類。

在原有的代碼上做小小的改動即可滿足。但是缺點是會有很多類,容易類爆炸,推薦在狀态類型不多的情況下使用狀态模式