![](/img/trans.png)
[英]How to enforce that a field/property represents a certain type of physical quantity?
[英]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.