舉個慄子 問題描述 上班的日子,上午狀態好,中午想睡覺,下午漸恢復,加班苦煎熬。根據時間的不同體現不同的工作狀態。 簡單實現 Work / 抽象狀態 Created by callmeDevil on 2019/8/3. / public abstract class State { public ...
舉個慄子
問題描述
上班的日子,上午狀態好,中午想睡覺,下午漸恢復,加班苦煎熬。根據時間的不同體現不同的工作狀態。
簡單實現
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點之前離開公司(想想就好,現實往往不可能。。),那就會對當前的方法改動,維護出錯的風險很大,這點來說違背了“開放-封閉原則”。
狀態模式
定義
當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。
狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把複雜的判斷邏輯簡化。當然,如果這個狀態判斷很簡單,那就沒必要用狀態模式了。
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 方法
}
測試代碼與測試結果同上。
總結
- 好處是將與特定狀態相關的行為局部化,並且將不同狀態的行為分割開來。
- 將特定的狀態相關的行為都放入一個對象中,由於所有與狀態相關的代碼都存在於某個 ConcreteState 中,所以通過定義新的子類可以很容易的增加新的狀態和轉換。
- 狀態模式通過把各種狀態轉移邏輯分佈到 State 的子類之間,來減少相互間的依賴。
- 當一個對象的行為取決於它的狀態,並且必須在運行時根據狀態改變它的行為時,就可以考慮使用狀態模式。