【发布时间】:2014-10-24 08:41:41
【问题描述】:
我正在为视频游戏中的游戏对象开发状态机实现。我希望这个状态机易于使用;为了调用状态变化,应该在状态机上调用“Raise”方法。我当前的设计涉及使用泛型类型作为事件标识符:
stateMachine.Raise<Event>();
有定义:
public void Raise<EventType>() where EventType : Event
然后状态机找到处理这种事件类型的状态,并根据它们提供的转换更新状态。我最初考虑使用字符串来识别事件类型,例如:
stateMachine.Raise("Event");
或和枚举:
stateMachine.Raise(GameObject.Event);
但我觉得这两种方法都有问题。字符串是两个灵活的,不能在编译时进行错误检查以确保它们有效。枚举无法扩展,限制事件对每个扩展 GameObject 的类的可用,使事件调用不必要地更长,并导致状态机内的类型检查问题。然而,使用类作为标识的方法意味着我在 GameObject 中声明事件,如下所示:
protected class SomeEvent : Event {}
protected class OtherEvent : Event {}
...
protected class AnotherEvent : Event {}
尽管很优雅,但我觉得在某些时候这会变成一种代码味道或糟糕的做法,我觉得我在滥用类的目的。最终,我的代码库中会出现数百个空类,我认为这是一个潜在的问题。真正的最佳选择是什么?
【问题讨论】:
-
你说枚举是一个限制,因为它不能被扩展。但是你为什么要扩展事件的信号呢?它只是状态机改变的触发器。您希望这些事件不仅仅是未来的信号吗?
-
事件聚合器模式通常使用类似的东西。通常你会有一些附加到事件的信息,但有时没有。当您想收到某事的通知但可能没有可以订阅的固定发布者时,它很有用。
-
@YuvalItzchakov 我不认为每个事件都会扩展很多,但这确实意味着每个新事件类都必须扩展 Event,因为 Raise 方法会检查这一点。它还可以允许特定类型的状态机,例如: HierarchicalStateMachine 它期望 HierarchicalEvent 的 Raise 方法可以不同地使用。
-
@mikez 我目前不确定信息。目前在该系统中使用事件只是为了在离散状态之间进行更改,例如;门已打开,事件“关闭”已引发,门现在已关闭。也许我想错了?
-
@sydan 假设您将拥有多个 Door 对象,您需要确定要更改哪个特定 Door 的状态。我认为你遇到的问题首先是有太多的事件,而提议的方案都没有解决这个问题。当事件种类太多时,系统将难以理解。
标签: c# class enums identifier state-machine