1. 程式人生 > >設計模式篇:狀態模式(一)

設計模式篇:狀態模式(一)

當我們用Unity進行場景切換時,可能會寫下如下程式碼:

using UnityEngine;
using UnityEngine.SceneManagement;

public class ReverseVersion : MonoBehaviour
{
    private string _state = "到早上了";

    public void ChanageScene(string StateName)
    {
        _state = StateName;

        switch (_state)
        {
            case "到早上了":
                Debug.Log("早上起來第一句,就給自己打個氣");
                SceneManager.LoadScene(0);
                break;
            case "到中午了":
                Debug.Log("我餓了,我困了");
                SceneManager.LoadScene(1);
                break;
            case "到晚上了":
                Debug.Log("我不行了");
                SceneManager.LoadScene(2);
                break;
            default:
                break;
        }
    }
}

 

這樣一看,沒啥問題,可是,當場景之間轉換的條件複雜了場景多了,那又會是怎樣的一副光景呢?

這個類也會越來越龐大,每增加一個場景,就要多一個case,無論任何場景,都需要它來改變。

再或者需要改一下需求和轉換條件,你要改動的程式碼又有多少呢?

責任太過重大,違背了我們的“單一職責原則

那就可以請出我們的的“狀態模式”來解決問題

關於狀態模式

  • 當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類。
  • 狀態模式主要解決的是當控制一個物件狀態轉換的條件表示式過於複雜的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類中,可以把複雜的判斷邏輯簡化。對於Unity場景的來說,由於Unity執行時只會有一個場景呈現在大家眼前。所以就顯得尤為適用場景之間的切換。
  • 當一個物件的行為取決於它的狀態,並且他必須在執行時根據狀態改變他的行為時,就可以考慮使用狀態模式了。

 

概念性的東西就這些,直接看專案

首先是State,他作為抽象類讓具體狀態繼承

    public abstract class State
    {
        public abstract void WriteProgram(Work w);
    }

然後是,早上,中午,下午,晚上四個類

    public class ForenoonState:State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 12)
            {
                Debug.Log("當前時間:" + w.Hour + "點 上午工作,精神百倍");
            }
            else
            {
                w.SetState(new NoonState());
                w.WriteProgram();
            }
        }
    }
public class NoonState:State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 13)
            {
                Debug.Log("當前時間:" + w.Hour + "點 餓了,午休;犯困,午休");
            }
            else
            {
                w.SetState(new AfternoonState());
                w.WriteProgram();
            }
        }
    }
 public class AfternoonState:State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 17)
            {
                Debug.Log("當前時間:" + w.Hour + "點 下午狀態還不錯,繼續努力");
            }
            else
            {
                w.SetState(new EveningState());
                w.WriteProgram();
            }
        }
    }
public class EveningState:State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour > 18)
            {
                Debug.Log("當前時間:" + w.Hour + "點 我不行了,要睡著了");
            }
        }
    }

然後是工作類,調控全部的工作狀態

public class Work
    {
        private State _current;

        public Work()
        {
            _current=new ForenoonState();
        }

        private double _hour;

        public double Hour
        {
            get { return _hour; }
            set { _hour = value; }
        }

        public void SetState(State s)
        {
            _current = s;
        }

        public void WriteProgram()
        {
            _current.WriteProgram(this);
        }
    }

測試指令碼

using System.Collections;
using System.Collections.Generic;
using DefaultNamespace;
using UnityEngine;


public class Test : MonoBehaviour {


	private void Start () {
		Work emergencyProject=new Work();
		emergencyProject.Hour = 9;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 10;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 12;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 13;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 14;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 17;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 21;
		emergencyProject.WriteProgram();
	}
	
	
}

在Unity建立場景,在場景建立一個空物體,把Test指令碼掛載在其上面

運行遊戲

這時,我們增加需求:

  1. 出於安全考慮,超過21點,全體員工必須回家
  2. 18點之後,做完工作的可以提前回家

增加下班類

    public class FuckingOutwork:State
    {
        public override void WriteProgram(Work w)
        {
            Debug.Log("下班了,溜了溜了");
        }
    }

更改工作類,增加結束工作欄位

        private bool _finish = false;

        public bool Finish
        {
            get { return _finish; }
            set { _finish = value; }
        }

更改晚上工作類如下

public class EveningState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Finish)
            {
                w.SetState(new FuckingOutwork());
                w.WriteProgram();
            }
            else
            {
                if (w.Hour <= 21)
                {
                    Debug.Log("當前時間:" + w.Hour + "點 我不行了,要睡著了");
                }
                else
                {
                    w.SetState(new FuckingOutwork());
                    w.WriteProgram();
                }
            }
        }
    }

Test指令碼增加一條22點的語句

emergencyProject.Hour = 22;
emergencyProject.WriteProgram();

再次執行

Test指令碼更改如下

using System.Collections;
using System.Collections.Generic;
using DefaultNamespace;
using UnityEngine;


public class Test : MonoBehaviour {


	private void Start () {
		Work emergencyProject=new Work();
		emergencyProject.Hour = 9;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 10;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 12;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 13;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 14;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 17;
		emergencyProject.WriteProgram();
		emergencyProject.Finish = true;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 21;
		emergencyProject.WriteProgram();
		emergencyProject.Hour = 22;
		emergencyProject.WriteProgram();
		 
	}
	
	
}

再次執行

我們發現,增加的這兩個判定條件需要改動的程式碼量很小。體現出了狀態模式的優點。

理論差不多瞭解,那麼我們就需要把它運用到實戰中!請看下集