狀态模式:當一個對象的内在狀态改變時允許改變其行為,這個對象看起來像是改變了其類
通俗解釋:改變一個狀态值時,其行為發生了改變。行為也就是做了什麼。
下面一個例子:(大話設計模式的例子)
一天之中的工作狀态随着時間改變
早晨-精神百倍
中午-犯困
下午-狀态不錯
(完成工作的情況)
傍晚-下班
(沒完成工作的情況)
傍晚-沒完成工作-加班
晚上-困得要死
結合這個例子,編寫代碼
@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()改為新建立的強制下班的子類,無須改動其他的子類。
在原有的代碼上做小小的改動即可滿足。但是缺點是會有很多類,容易類爆炸,推薦在狀态類型不多的情況下使用狀态模式