設(shè)計(jì)模式之狀態(tài)模式與外觀模式

狀態(tài)模式代碼原型

解決的問題:
  主要解決的是當(dāng)控制一個(gè)對象狀態(tài)轉(zhuǎn)換的條件表達(dá)式過于復(fù)雜時(shí)的情況。把狀態(tài)的判斷邏輯轉(zhuǎn)移到表示不同的一系列類當(dāng)中,可以把復(fù)雜的邏輯判斷簡單化。

模式中的角色
  1 上下文環(huán)境(Context):它定義了客戶程序需要的接口并維護(hù)一個(gè)具體狀態(tài)角色的實(shí)例,將與狀態(tài)相關(guān)的操作委托給當(dāng)前的Concrete State對象來處理。
  2 抽象狀態(tài)(State):定義一個(gè)接口以封裝使用上下文環(huán)境的的一個(gè)特定狀態(tài)相關(guān)的行為。
  3 具體狀態(tài)(Concrete State):實(shí)現(xiàn)抽象狀態(tài)定義的接口。

狀態(tài)模式原型代碼的實(shí)現(xiàn):

using UnityEngine;

public class StateDesi : MonoBehaviour
{
    private void Start()
    {
        Context context = new Context();
        context.SetState(new ConcreteStateA(context));
        context.ContextHandle(5);
        context.ContextHandle(20);
        context.ContextHandle(30);
        context.ContextHandle(4);    
    }
}

//狀態(tài)的擁有者
public class Context
{
    private IState mState;

    public void SetState(IState state)
    {
        mState = state;
    }
    public void ContextHandle( int arg)
    {
        mState.Handle(arg);
    }
}

public interface IState
{
    //處理當(dāng)前狀態(tài)的行為
    void Handle(int arg);
}

public class ConcreteStateA : IState
{
    private  Context mContext;

    public ConcreteStateA(Context context)
    {
        mContext = context;
    }

    public void Handle(int arg)
    {
        Debug.Log("ConcreteStateA.Handle"+arg);
        if (arg > 10)
        {
            mContext.SetState(new ConcreteStateB(mContext));

        }
    }
}
public class ConcreteStateB : IState
{
    private Context mContext;

    public ConcreteStateB(Context context)
    {
        mContext = context;
    }

    public void Handle(int arg)
    {
        Debug.Log("ConcreteStateB.Handle" + arg);
        if (arg <= 10)
        {

            mContext.SetState(new ConcreteStateA(mContext));
        }
    }
}

輸出結(jié)果:
首先設(shè)置的初始狀態(tài)是ConcreteStateA,然后然后判斷arg是否大于10,如果大于10就切換到ConcreteStateB狀態(tài),到達(dá)ConcreteStateB狀態(tài)后每次有判斷arg是否小于等于10,如果小于等于又切換到ConcreteStateA狀態(tài),這就是狀態(tài)直接的相互切換。


image.png

場景狀態(tài)跳轉(zhuǎn)栗子

下面我舉例子來實(shí)現(xiàn)狀態(tài)模式下場景狀態(tài)的跳轉(zhuǎn),首先來看看,下面有三個(gè)場景狀態(tài),首先是開始界面,顯示完Logo后馬上跳轉(zhuǎn)到游戲主界面場景狀態(tài),點(diǎn)擊開始游戲有跳轉(zhuǎn)到戰(zhàn)斗場景狀態(tài)


image.png

創(chuàng)建三個(gè)場景分別命名為StartScene,MainScene,BattleScene。在StartScene場景里創(chuàng)建 GameLoop 游戲?qū)ο?,并在其上掛載GameLoop腳本.

image.png
using UnityEngine;

public class GameLoop : MonoBehaviour {

    private SceneStateController controller=null; 

    public void Awake()
    {
        DontDestroyOnLoad(this.gameObject);//跳轉(zhuǎn)場景也不刪除此游戲?qū)ο?    }

    // Use this for initialization
    void Start () {
        controller = new SceneStateController();

        controller.SetState(new StartState(controller),false);//設(shè)置默認(rèn)狀態(tài)(初始狀態(tài))
    }
    
    // Update is called once per frame
    void Update () {
        controller.StateUpdate();
    }
}

然后就是創(chuàng)建狀態(tài)擁有者SceneController腳本

using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneStateController
{
    private ISceneState mState;
    private AsyncOperation mAO;
    //控制StateStart只調(diào)用一次
    private bool mIsRunStart = false;

    public void SetState(ISceneState state, bool isLpadScene=true)
    {
        if (mState != null)//如果當(dāng)前有狀態(tài)
        {
            mState.StateEnd();//讓上一個(gè)場景狀態(tài)做清理工作
        }
        mState = state;//設(shè)置狀態(tài)

        //isLpadScene是否需要加載場景,因?yàn)樽铋_始的場景是不需要加載的
        if (isLpadScene)
        {
             mAO = SceneManager.LoadSceneAsync(mState.SceneName);
            mIsRunStart = false;
        }
        else
        {
            mState.StateStart();
            mIsRunStart = true;
        }

    }

    public void StateUpdate()
    {
        //正在加載場景的時(shí)候
        if (mAO != null && mAO.isDone == false) return;
        //場景加載完成  mAO.isDone == true如果場景加載完成才調(diào)用StateStart方法
        if (mIsRunStart==false&&mAO != null && mAO.isDone == true)
        {
            mState.StateStart();
            mIsRunStart = true;
        }

        if (mState != null)
        {
            mState.StateUpdata();//場景狀態(tài)下每幀更新
        }
    }
}

下面就是各個(gè)狀態(tài)的基類,

public class ISceneState
{
    private string mSceneName;
    protected SceneStateController mController;

    public ISceneState(string sceneName,SceneStateController controller)
    {
        mSceneName = sceneName;
        mController = controller;
    }

    public string SceneName
    {
        get { return mSceneName; }
    }
    //每次進(jìn)入這個(gè)狀態(tài)的時(shí)候調(diào)用
    public virtual void StateStart() { }
    //這個(gè)狀態(tài)下每幀更新
    public virtual void StateUpdata(){}
    //退出這個(gè)狀態(tài)的時(shí)候調(diào)用
    public virtual void StateEnd() { }
}

下面是三個(gè)場景狀態(tài)類繼承ISceneState

using UnityEngine;
using UnityEngine.UI;

public class StartState : ISceneState
{
    public StartState(SceneStateController controller) : base("StartScene", controller)
    {
    }
    private Image mLogo;
    private float mSmoothingTime = 0.5f;
    private float mWaitTime = 2;
    public override void StateStart()
    {
        
        mLogo = GameObject.Find("Logo").GetComponent<Image>();//查找開始面板
        mLogo.color = Color.black;//初始設(shè)置為黑色
    }
    public override void StateUpdata()
    {
        mLogo.color = Color.Lerp(mLogo.color,Color.white, mSmoothingTime*Time.deltaTime);//從黑色跳轉(zhuǎn)到白色
        mWaitTime -= Time.deltaTime;
        if (mWaitTime<=0)//兩秒后跳轉(zhuǎn)到第二個(gè)場景
        {
            mController.SetState(new MainState(mController));
        }

    }
}
using UnityEngine;
using UnityEngine.UI;

public class MainState : ISceneState
{
    public MainState(SceneStateController controller) : base("MainScene", controller)
    {
    }
  
    public override void StateStart()
    {

        GameObject.Find("StartButton").GetComponent<Button>().onClick.AddListener(OnClick); ;//給Button注冊按鈕事件
    }
    private   void OnClick()
    {
        mController.SetState(new BattleState(mController));//跳轉(zhuǎn)到第三個(gè)場景
    }
}
public class BattleState : ISceneState
{
    public BattleState( SceneStateController controller) : base("BattleScene", controller)
    {
    }
}
fdsfsfgr.gif

外觀模式

外觀模式定義:
為子系統(tǒng)中的一組接口提供一個(gè)統(tǒng)一的入口。外觀模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。
概述:
外觀模式通過引入一個(gè)外觀角色來簡化客戶端與子系統(tǒng)之間的交互,為復(fù)雜的子系統(tǒng)調(diào)用提供一個(gè)統(tǒng)一的入口,降低子系統(tǒng)與客戶端的耦合度,且客戶端調(diào)用非常方便。

外觀模式實(shí)現(xiàn):
外觀模式通過引入一個(gè)新的外觀類(Facade)來實(shí)現(xiàn)該功能,外觀類充當(dāng)了軟件系統(tǒng)中的“服務(wù)員”,它為多個(gè)業(yè)務(wù)類的調(diào)用提供了一個(gè)統(tǒng)一的入口,簡化了類與類之間的交互。在外觀模式中,那些需要交互的業(yè)務(wù)類被稱為子系統(tǒng)(Subsystem)。如果沒有外觀類,那么每個(gè)客戶類需要和多個(gè)子系統(tǒng)之間進(jìn)行復(fù)雜的交互,系統(tǒng)的耦合度將很大,如圖2(A)所示;而引入外觀類之后,客戶類只需要直接與外觀類交互,客戶類與子系統(tǒng)之間原有的復(fù)雜引用關(guān)系由外觀類來實(shí)現(xiàn),從而降低了系統(tǒng)的耦合度,如圖2(B)所示。

外觀模式中,一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信通過一個(gè)統(tǒng)一的外觀類進(jìn)行,外觀類將客戶類與子系統(tǒng)的內(nèi)部復(fù)雜性分隔開,使得客戶類只需要與外觀角色打交道,而不需要與子系統(tǒng)內(nèi)部的很多對象打交道。
代碼實(shí)現(xiàn)

class SubSystemA  
{  
    public void MethodA()  
    {  
        //業(yè)務(wù)實(shí)現(xiàn)代碼  
    }  
}  
  
class SubSystemB  
{  
    public void MethodB()  
    {  
        //業(yè)務(wù)實(shí)現(xiàn)代碼  
     }  
}  
  
class SubSystemC  
{  
    public void MethodC()  
    {  
        //業(yè)務(wù)實(shí)現(xiàn)代碼  
    }  
}  
class Facade  
{  
    private SubSystemA obj1 = new SubSystemA();  
    private SubSystemB obj2 = new SubSystemB();  
    private SubSystemC obj3 = new SubSystemC();  
  
    public void Method()  
    {  
        obj1.MethodA();  
        obj2.MethodB();  
        obj3.MethodC();  
    }  
}  
class Program  
{  
    static void Main(string[] args)  
    {  
        Facade facade = new Facade();  
        facade.Method();  
    }  
}  

借鑒自:
深入淺出外觀模式
設(shè)計(jì)模式學(xué)習(xí)筆記-狀態(tài)模式

單例模式:
http://blog.csdn.net/carson_ho/article/details/52223097
http://blog.csdn.net/iblade/article/details/51107308

設(shè)計(jì)模式之中介者模式(Mediator):
http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/30/2663922.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容