是否更好地创建具有多个函数或创建类的库?

时间:2011-01-27 17:56:40

标签: oop refactoring

我正在开发一种与设备通信的软件。

软件将为设备发送命令。设备必须使用以下协议回答:

<STX><STX><COMMAND>[<DATA_1><DATA_2>...<DATA_N>]<CHKSUM><ETX>

其中:

<STX> is the Start of TeXt (0x55);
<COMMAND> can be 0x01 for read, 0x02 for write, etc;
<DATA> is any value;
<CHKSUM> is the checksum;
<ETX> is the End of TeXt (0x04).

所以,我必须验证收到的数据。

然后,收到的数据:

  • 不能为空;
  • 必须包含3个或更多字符;
  • 必须在字符串数据的前两个字符中包含标题;
  • 必须在字符串数据的最后一个字符中有一个“页脚”;
  • 必须拥有有效的CheckSum。

如果答案有效,那么我可以处理数据。但在此之前我必须从收到的回复中提取这些数据。

好的,这是一项相对容易的任务。之前我会以程序的方式进行,只使用一个函数并放入许多if。

现在我正在研究更好的编程实践,事情似乎越来越难。

要验证设备答案,最好创建一个类“ValidateReceivedData”,并在此类的构造函数中传递接收的数据?然后创建一个名为“IsReceivedDataValid”的公共方法,检查上面给出的所有步骤?

或者更好的是创建一个具有多个函数的库来验证收到的数据?

我也想使用单元测试。

正如我之前所说,我正在研究更多以制作更好的代码。但我意识到我现在花费的时间比以前更多。并且有太多问题出现了,但在我看来,它们似乎很容易解决,但我没有得到。

3 个答案:

答案 0 :(得分:2)

对于它的价值,我在使用面向对象设计之前已经做过这类事情。这是您设计的高级可能性:

ProtocolParser上课:

  • 在构造函数中使用SerialPort对象或等效对象,并侦听传入的字节
  • 将收到的字节传递给OnByteReceivedUnknown实现特定于协议的状态机(状态为Stx1ReceivedStx2ReceivedCkSumReceived,...,{{1 }})。
  • 收到完整的好消息后,创建一个Packet类型的对象,该对象在其构造函数中接受一个字节列表。然后它会引发一个事件PacketReceived,并将Packet作为参数传递。
  • 如果收到错误字节,它会引发事件BadDataReceived并传递错误数据(可能是为了记录/调试目的)。

Packet上课:

  • 获取一个列表/字节数组,并将它们存储为CommandData属性。
  • 不需要保存校验和,因为此类仅用于表示有效数据包。

上述类足以实现接收协议。您应该能够通过模拟SerialPort类来测试它(即,ProtocolParser实际上可以使用IDataSource而不是SerialPort。)

然后,您可以添加更高级别的类来实现特定于设备的功能,这些功能可以收听PacketReceived的{​​{1}}事件。

答案 1 :(得分:1)

当然最好使用OOP设计 根据你的解释,我至少要上两节课:

  1. 消息

  2. 执行器

  3. 该消息将从设备接收命令,Executer将处理该消息。

    Message对象将以设备的答案启动。它会解析它,按照你的描述保持字段:

    STX
    COMMAND
    数据
    CHKSUM
    ETX

    然后Executer对象将接收Message对象并执行消息的实际执行,并保存逻辑代码。

答案 2 :(得分:1)

我会比Yochai的答案更进一步,并创建以下类:

  1. 命令:实际上不是一个类,而是一个Enum值,所以你可以检查Command.Read等,而不仅仅是“知道”0x01和0x02是什么意思。
  2. 消息:只是一个普通对象(PO​​JO / POCO /无论什么),用于保存消息的数据表示。这将包含以下字段:
    1. 命令(前面提到的枚举类型)
    2. 数据:数据列表。根据数据的表示方式,您可以为此创建一个类,或者您可以将每个数据表示为字符串。
  3. MessageParser:这将有一个解析字符串或文本流并创建Message对象的函数。如果文本无效,我会抛出一个自定义的异常(另一个类),可以被调用者捕获。
  4. MessageExecutor:这将采用Message对象并执行它所代表的操作。
  5. 通过制作中间表示对象(Message),您可以分离您正在执行的各种操作。例如,如果Powers That Be决定可以将消息文本作为XML或JSON发送,则可以创建不同的MessageParser类,而不必弄乱决定如何处理消息的逻辑。

    这也使得单元测试变得更加容易,因为您可以独立于执行程序测试消息解析器。首先通过调用解析函数并检查生成的Message对象来测试消息解析器。然后通过创建Message对象并确保采取适当的操作来测试执行程序。