大話設計模式筆記(十三)の狀態模式

舉個栗子

問題描述

上班的日子,上午狀態好,中午想睡覺,下午漸恢復,加班苦煎熬。根據時間的不一樣體現不一樣的工做狀態。安全

簡單實現

Work

/**
 * 工做類
 * Created by callmeDevil on 2019/8/3.
 */
public class Work {

    private int hour;
    private boolean finish = false;

    public void writeProgram() {
        if (hour < 12) {
            System.out.println(String.format("當前時間:%s點,上午工做,精神百倍", hour));
        } else if (hour < 13) {
            System.out.println(String.format("當前時間:%s點,餓了,午餐;犯困,午休", hour));
        } else if (hour < 17) {
            System.out.println(String.format("當前時間:%s點,下午狀態還不錯,繼續努力", hour));
        } else {
            if (finish) {
                System.out.println(String.format("當前時間:%s點,下班回家了", hour));
            } else {
                if (hour < 21) {
                    System.out.println(String.format("當前時間:%s點,加班哦,疲累至極", hour));
                } else {
                    System.out.println(String.format("當前時間:%s點,不行了,睡着了", hour));
                }
            }
        }
    }

    // 省略 get set 方法

}

測試

public class Test {
    public static void main(String[] args) {
        // 緊急項目
        Work emergencyProjects = new Work();
        emergencyProjects.setHour(9);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(10);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(11);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(12);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(13);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(14);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(17);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
        System.out.println("--------------------------");
        emergencyProjects.setFinish(true);
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
    }
}

測試結果

當前時間:9點,上午工做,精神百倍
當前時間:10點,上午工做,精神百倍
當前時間:11點,上午工做,精神百倍
當前時間:12點,餓了,午餐;犯困,午休
當前時間:13點,下午狀態還不錯,繼續努力
當前時間:14點,下午狀態還不錯,繼續努力
當前時間:17點,加班哦,疲累至極
當前時間:19點,加班哦,疲累至極
當前時間:22點,不行了,睡着了
--------------------------
當前時間:19點,下班回家了
當前時間:22點,下班回家了

存在問題

面向對象設計其實就是但願作到代碼的責任分解。 這個類違背了「單一職責原則」。若是公司爲了員工的安全而要求員工必須20點以前離開公司(想一想就好,現實每每不可能。。),那就會對當前的方法改動,維護出錯的風險很大,這點來講違背了「開放-封閉原則」。ide

狀態模式

定義

當一個對象的內在狀態改變時容許改變其行爲,這個對象看起來像是改變了其類。

狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的狀況。把狀態的判斷邏輯轉移到表示不一樣狀態的一系列類當中,能夠把複雜的判斷邏輯簡化。固然,若是這個狀態判斷很簡單,那就不必用狀態模式了。測試

UML圖

代碼實現

State

/**
 * 抽象狀態
 * Created by callmeDevil on 2019/8/3.
 */
public abstract class State {
    public abstract void writeProgram(Work work);
}

ForenoonState

/**
 * 上午工做狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class ForenoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 12) {
            System.out.println(String.format("當前時間:%s點,上午工做,精神百倍", work.getHour()));
        } else {
            // 超過12點,轉入中午工做狀態
            work.setState(new NoonState());
            work.writeProgram();
        }
    }
}

NoonState

/**
 * 中午工做狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class NoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 13) {
            System.out.println(String.format("當前時間:%s點,餓了,午餐;犯困,午休", work.getHour()));
        } else {
            // 超過13點,轉入下午工做狀態
            work.setState(new AfternoonState());
            work.writeProgram();
        }
    }
}

AfternoonState

/**
 * 下午工做狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class AfternoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 17) {
            System.out.println(String.format("當前時間:%s點,下午狀態還不錯,繼續努力", work.getHour()));
        } else {
            // 超過17點,轉入傍晚工做狀態
            work.setState(new EveningState());
            work.writeProgram();
        }
    }
}

EveningState

/**
 * 傍晚工做狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class EveningState extends State {
    @Override
    public void writeProgram(Work work) {
        if (work.isTaskFinished()) {
            // 若是完成任務,轉入下班狀態
            work.setState(new RestState());
        } else {
            if (work.getHour() < 21) {
                System.out.println(String.format("當前時間:%s點,加班哦,疲累至極", work.getHour()));
            } else {
                // 超過21點,轉入睡眠工做狀態
                work.setState(new SleepingState());
                work.writeProgram();
            }
        }
    }
}

SleepingState

/**
 * 睡眠工做狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class SleepingState extends State{
    @Override
    public void writeProgram(Work work) {
        System.out.println(String.format("當前時間:%s點,不行了,睡着了", work.getHour()));
    }
}

RestState

/**
 * 下班工做狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class RestState extends State{
    @Override
    public void writeProgram(Work work) {
        System.out.println(String.format("當前時間:%s點,下班回家了", work.getHour()));
    }
}

Work

/**
 * 工做類,此時沒有了過長的分支判斷語句
 * Created by callmeDevil on 2019/8/3.
 */
public class Work {

    private State current;
    private int hour; // 時間,狀態轉換的依據
    private boolean taskFinished; // 任務完成,是否能下班的依據

    public Work(){
        // 工做初始化爲上午工做狀態,即上午9點開始上班
        current = new ForenoonState();
    }

    public void writeProgram(){
        current.writeProgram(this);
    }

    // 省略 get set 方法

}

測試代碼與測試結果同上。this

總結

  • 好處是將與特定狀態相關的行爲局部化,而且將不一樣狀態的行爲分割開來。
  • 將特定的狀態相關的行爲都放入一個對象中,因爲全部與狀態相關的代碼都存在於某個 ConcreteState 中,因此經過定義新的子類能夠很容易的增長新的狀態和轉換。
  • 狀態模式經過把各類狀態轉移邏輯分佈到 State 的子類之間,來減小相互間的依賴。
  • 當一個對象的行爲取決於它的狀態,而且必須在運行時根據狀態改變它的行爲時,就能夠考慮使用狀態模式。
相關文章
相關標籤/搜索