1

我正在为游戏编写 StateManager(我正在使用 C++ 和 SFML,但我试图隐藏特定于语言的元素,因为这是关于任何 OOP 语言的问题)。我有一个设置,其中 StateManager 更新当前的活动状态。但是,State 必须能够更改活动状态(例如,在菜单中按“Play”会启动 PlayingState),因此我在我的 State 类中保留对 StateManager 的引用。

这是一个让事情更清楚的UML图。 UML 图状态管理器

如您所见,StateManager 和 State 都相互引用。我怎样才能避免意大利面条代码?我应该将 StateManager 设为单例类吗?当我们这样做时,游戏类应该是单例类吗?我可以轻松做到这一点,但我真的不喜欢我的游戏中的其他类能够访问游戏类或 statemanager 类,即使我是唯一的程序员。

4

2 回答 2

1

双向引用没有错。查看 Qt 的 QWidgets 的父/子模型。如果每个 State 只能影响一个 StateManager,则让每个 State 在其构造中获取一个指向 StateManager“父级”的指针,或者稍后设置它。StateManager 可以在集合中跟踪它的“孩子”,每个孩子都知道它的父母是谁,所以它可以通知那个父母任何变化。

编辑:我认为首先要看的是打破你的州级。目前,它既代表一种状态,也代表一种转变为该状态的动作。Actions 应该知道 StateMachine,告诉它改变状态。状态应该在 StateMachine 内部。

于 2013-04-02T09:34:25.243 回答
1

您需要在合同中进行设计,也称为接口。例如,状态(原则上)不需要访问状态机。但是,状态的实现可能需要访问。C# 中的示例:

public interface IState
{
    void Render();
    void Update();
}

public interface IStateMachine
{
    void ChangeState(IState newState);
}

public class MenuState : IState
{
    private IStateMachine _stateMachine;

    public MenuState(IStateMachine stateMachine)
    {
        _stateMachine = stateMachine;
    }

    public void Render()
    {
    }

    public void Update()
    {
    }
}

public class StateMachineImplementation : IStateMachine
{
    public void ChangeState(IState newState)
    {
    }
}

通知IState的任何实现都不知道任何IStateMachine实现,它们只是在合同上工作。另请注意,MenuState不关心“IStateMachine”的来源(控制反转),它只是使用它。

如果需要,您可以在IStateMachinefor中添加另一个函数。GetStates()

最终,您使用这些合约来避免耦合;这意味着您可以完全替换IStateManagerand 的实现(假设遵守合同),MenuState仍然可以正常工作。

于 2013-04-02T09:39:36.570 回答