不幸的是,我不得不与一些看似处于不断变化的固件接口(USB通信协议不断变化,寄存器/地址映射不断变化,各种状态机不断变化等)。< / p>
我设法实现了一个合理的界面,所以实际上与固件通信并不太困难。
我的主要问题是代表不同的状态机,其中大约有十几个。在他们改变之前我只有一个枚举,例如:
public enum Component1StateType
{
RESET = 0,
INITIALISING = 1,
READY = 2,
WAITING = 3
}
然后我在主代码中自由使用,根据系统状态修改软件的行为。
现在我遇到了一个问题,即较新的固件Component1StateType
已更改为以下内容:
public enum Component1StateType
{
RESET = 0,
INITIALISING = 1,
INITIALISED = 2,
READY = 3,
ERROR = 4,
STANDBY = 5,
WAITING = 6
}
然后会破坏主程序中所有以前的状态处理代码,当然必须支持所有不同版本的固件。
我正在努力想出一种很好的方式来代表这些不同的状态机,这意味着主代码不会像以下那样散落:
if (stateMachineVersion == 1)
{
//code branch for version 1
}
else if(stateMachineVersion == 2)
{
//code branch for version 2
}
...
...
关于如何最好地应对这些不断变化的状态的任何想法?
答案 0 :(得分:2)
为状态机创建一个接口,并在顶层公开enum
,而不向状态机类外的程序提供任何数值:
interface HardwareConnector {
Component1StateType CurrentState {get;}
... // Other properties and methods
}
public enum Component1StateType {
Reset
, Initializing
, Initialized
, Ready
, Error
, Standby
, Waiting
}
根据需要支持的硬件版本,对HardwareConnector
接口进行不同的实现。您的代码应该编程到HardwareConnector
接口。代码唯一应该知道的地方#34;关于每个硬件版本的类实现是初始化,在那里你检测另一端的硬件。
在每个实现类中,您可以将私有enum
与接口级别可见的Component1StateType
枚举断开连接。
internal enum Component1StateTypeV1 {
RESET = 0,
INITIALISING = 1,
READY = 2,
WAITING = 3
}
internal enum Component1StateTypeV2 {
RESET = 0,
INITIALISING = 1,
INITIALISED = 2,
READY = 3,
ERROR = 4,
STANDBY = 5,
WAITING = 6
}
该类的内部使用私有enum
值来执行其工作,然后在State
getter的实现中将其私有值转换为公共值:
public Component1StateTypeV {
get {
switch (internalState) {
case Component1StateTypeV1.RESET : return Component1StateTypeV.Reset;
case Component1StateTypeV1.INITIALISING : return Component1StateTypeV.Initializing;
case Component1StateTypeV1.READY : return Component1StateTypeV.Ready;
case Component1StateTypeV1.WAITING : return Component1StateTypeV.Waiting;
}
throw new InvalidOperationException();
}
}
答案 1 :(得分:1)
我有一些真实世界的经验,因为我维持一项服务,必须处理来自各种远程信息处理跟踪单元(&#34;调制解调器&#34;)的数千个并发连接,其中一些是主题的变体来自同一制造商,其中一些有非常不同的协议。当我第一次遇到这个代码时,大部分工作都是在一个单独的类中完成的,如果我没记错的话,大约有10,000行代码!几年前我将它重构为一个OOP模型,从那时起它就变得更加容易。
我有一个用于调制解调器的抽象基类,以及每种调制解调器类型的不同级别的派生类。在游戏中还有几个代表各种行为的界面。我建议你重构如下内容:
internal abstract class Device // Generic name here as I don't know what kind of device you are talking to {
// Common code here
// abstract and/or virtual members here for the different behaviours in the various firmware versions
}
internal sealed class DeviceFirmwareA : Device
{
// Private, firmware-specific enumerations here
// Overrides here
}
internal sealed class DeviceFirmwareB : Device
{
// Private, firmware-specific enumerations here
// Overrides here
}
当然你还需要:
对不起,我对其他步骤含糊不清,因为我需要查看相关的现有代码,但如果沿着这条路走下去,我确定你可以使用它出!
答案 2 :(得分:0)
public enum Component1StateType
{
RESET = 0,
INITIALISING = 1,
READY = 2,
WAITING = 4,
INITIALISED = 5,
// etc
}
它不会破坏旧版本。
接下来,准备可以这样使用的属性:
public enum Component1StateType
{
RESET = 0,
INITIALISING = 1,
[StateMapping(MachineStateVersion = 2, Value = 3)]
READY = 2,
[StateMapping(MachineStateVersion = 2, Value = 4)]
WAITING = 3,
[StateMapping(MachineStateVersion = 2, Value = 2)]
INITIALISED = 5,
// etc
}
该属性可以多次用于各种范围的machnie state版本。 然后准备扩展方法:
public static bool IsInState(this Enum enum, int machineStateVersion, Component1StateType value)
{
// fetch proper mapped value via reflection from attribute basing on machineState
}
用法:
Component1StateType currentState = // val from some;
if (currentState.IsInState(CURRENT_MACHINE_STATE_VERSION,
Component1StateType.INITIALISING))
{
//
}
<强>赞成强>
<强>缺点强>