簡體   English   中英

如何在沒有類型問題的情況下在派生的 class 上強制執行 object 字段或屬性?

[英]How to enforce an object field or property on a derived class without type issues?

我正在 Unity 3D 中制作回合制游戲。 由於它是回合制的,我正在嘗試實現一個 state 機器來控制游戲的一般流程。 玩家將控制多個單位,就像在 XCOM 等游戲中一樣,我認為每個單位的 state 機器也可能有助於控制一個單位是否空閑、當前選擇、銷毀等。武器可能也可以使用它們與狀態比如閑置和瞄准。

關鍵是,我正在嘗試盡可能地抽象我的 state 邏輯,因此它在不同的 state 機器中是通用的,同時還要干燥我的代碼,所以我不會重復。 為了實現這一點,我當然會使用接口,例如我的 IState 接口:

namespace MechGame.Common.States
{
    public interface IState
    {
        void EnterState();
        void ExitState();
        void UpdateState();
    }
}

當我嘗試在派生類上強制執行字段時,問題就來了。 我被多次告知將接口視為合同,告訴 class “你必須實現 X、Y 和 Z”。 我知道我的 state 機器邏輯中的一些對象需要一些私有成員字段。 我想在我的基類中聲明這些字段,以便干掉我的代碼,幾乎像接口強制方法一樣強制它們。 問題是如何以抽象的方式聲明這些 object 字段的類型? 例如,每台 state 機器都有一個 state 管理器,它擴展了 StateManager class:

namespace MechGame.Common.States
{
    public interface IStateManager
    {
        State CurrentState { get; }
        void NextState();
        void TransitionToState(State state);
    }
}
using UnityEngine;

namespace MechGame.Common.States
{
    public abstract class StateManager : MonoBehaviour, IStateManager
    {
        protected State _current;
        public State CurrentState { get => _current; }

        public abstract void NextState();

        public virtual void TransitionToState(State state)
        {
            if(_current != null)
                _current.ExitState();

            _current = state;
            _current.EnterState();
        }

        public virtual void Update()
        {
            _current.UpdateState();
        }
    }
}

例如,我有一個名為 CombatStateManager 的 class,它擴展了 StateManager 並將控制游戲流程、玩家轉向、敵人轉向等。問題是當我需要引用 StateManager 的 CurrentState 字段之類的東西時,它是抽象類型 State,我需要將其轉換為更具體的內容,例如在以下 class 的 OnCellClick 方法中:

using MechGame.Common.States;
using MechGame.Selection;

namespace MechGame.Combat.States
{
    public class CellEventDispatcher : IStateEventDispatcher
    {
        private CombatStateManager _manager;

        public CellEventDispatcher(CombatStateManager manager)
        {
            _manager = manager;
        }

        public void DeregisterEventHandlers()
        {
            SelectionManager.OnCellClick -= OnCellClick;
        }

        void OnCellClick(int cellIndex, int buttonIndex)
        {
            ((CombatState)_manager.CurrentState).CellEventHandler.OnCellClick(cellIndex, buttonIndex);
        }

        public void RegisterEventHandlers()
        {
            SelectionManager.OnCellClick += OnCellClick;
        }
    }
}

這似乎沒什么大不了的,但這是一個在許多地方開始出現的問題。 基本上,就像接口如何強制必須實現某些方法一樣,我想讓我的基類強制任何子類實現一些必要的字段。 但它會導致類型問題,如上所示。 沒有像我想要的那樣在子類上強制執行字段的好方法嗎? 如果沒有,我還能如何干掉該代碼? 我對 generics 不太了解,這在這里有用嗎?

您可以實現一個通用變體。 雖然這只適用於每個 StateManager 始終只使用相同類型的 state 的情況。

例如:

    public interface IStateManager<TState> where TState : IState
    {
        TState CurrentState { get; }
        void NextState();
        void TransitionToState(TState state);
    }

    public class StateManager<TState>
     :  MonoBehaviour, IStateManager<TState> where TState : IState
    {
        //...
    }

    public class CombatStateManager : StateManager<CombatState>
    {
        //...
    }

現在,當您在CombatStateManager實例上訪問CurrentState時,它將始終是CombatState 這里的重點是永遠 所以它不能是另一個 state 類型(除非從 CombatState 派生)。

另外,作為一個插件。 沒有必要同時擁有抽象基礎 class 和接口。 除非您計划將接口作為一個也將包含在其他不相關的類中的東西,否則抽象基礎就足夠了。 您對接口功能的定義並沒有錯,但實際上它更適合將其視為“插件”功能,或者您所追求的某種“多繼承”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM