创建一个具有多个函数的库还是创建类更好?

发布于 2024-10-14 11:54:27 字数 1020 浏览 3 评论 0原文

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

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

<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 个或更多字符;
  • 字符串数据的前两个字符中必须有一个标题;
  • 字符串数据的最后一个字符必须有一个“页脚”;
  • 必须有一个有效的校验和。

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

好的,这是一个相对容易的任务。以前我会以一种程序的方式来完成它,只使用一个函数并放置许多 if。

现在我正在更多地研究良好的编程实践,事情似乎变得越来越难做了。

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

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

我也想使用单元测试。

正如我之前所说,我正在学习更多知识以编写更好的代码。但我意识到我现在花在编码上的时间比以前更多了。出现了太多的问题,但在我看来,它们似乎很容易解决,但我却没有得到解决。

I'm developing a software to comunicate with a device.

The software will send commands for the device. The device has to answer using the protocol below:

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

where:

<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).

So, I have to validate the received data.

Then, the received data:

  • cannot be empty;
  • must have 3 or more characters;
  • must have an header in the first two characters of the string data;
  • must have a "footer" in the last character of the string data;
  • must hava a valid CheckSum.

If the answer is valid, then I can handle the data. But before I'll have to extract this data from the response received.

Ok, this is a relatively easy task. Beforetime I would do it on a procedural way, using only one function and putting many if's.

Now I'm studying more about good programming practices, things seem to be getting harder to do.

To validate the device answer, is better create a class "ValidateReceivedData" for example and pass the received data in the constructor of this class? And then create a public method called "IsReceivedDataValid" that check all steps given above?

Or maybe would be better create a library with with several functions to validate the received data?

I'd like to use unit test too.

As I said before, I'm studying more to make better code. But I realize that I'm spending more time now to code than before. And there are too many questions that are arising, but in my view they seem easy to solve, but I'm not getting.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

独夜无伴 2024-10-21 11:54:27

无论如何,我在使用面向对象设计之前就做过这类事情。以下是您的设计的高级可能性:

ProtocolParser 类:

  • 在构造函数中采用 SerialPort 对象或等效对象,并监听它以获取传入字节
  • 将接收到的字节传递给 OnByteReceived,它实现特定于协议的状态机(具有诸如 UnknownStx1ReceivedStx2Received 等状态,... CkSumReceived)。
  • 收到完整的好消息后,创建一个 Packet 类型的对象,该对象在其构造函数中接受字节列表。然后,它引发一个事件 PacketReceived,并将 Packet 作为参数传递。
  • 如果接收到坏字节,它会引发一个事件 BadDataReceived 并传递坏数据(也许用于日志记录/调试目的)。

Packet 类:

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

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

然后,您可以添加一个更高级别的类来实现特定于设备的函数,该函数将侦听 ProtocolParserPacketReceived 事件。

For what it's worth, I've done this sort of thing before using object-oriented design. Here's a high level possibility for your design:

ProtocolParser class:

  • Takes a SerialPort object, or equivalent, in the constructor and listens to it for incoming bytes
  • Passes received bytes to OnByteReceived, which implements the protocol-specific state machine (with states like Unknown, Stx1Received, Stx2Received, ..., CkSumReceived).
  • After an entire good message is received, creates an object of type Packet, which accepts a byte list in its constructor. It then raises an event PacketReceived, passing the Packet as an argument.
  • If a bad byte is received, it raises an event BadDataReceived and passes the bad data (for logging/debugging purposes, perhaps).

Packet class:

  • Takes a list/array of bytes and stores them as Command and Data properties.
  • Does not need to save the checksum, as this class is only meant to represent a valid packet.

The above classes are sufficient to implement the receive protocol. You should be able to test it by mocking a SerialPort class (i.e., the ProtocolParser could actually take an IDataSource instead of a SerialPort).

You could then add a higher-level class to implement your device-specific functions, which would listen to the PacketReceived event of the ProtocolParser.

触ぅ动初心 2024-10-21 11:54:27

当然使用OOP设计会更好。
根据您的解释,我将至少创建 2 个类:

  1. Message

  2. Executer

该消息将接收来自设备的命令,并且执行器将处理该消息。

消息对象将以设备的应答启动。它将解析它,并保存您所描述的字段:

STX
命令
数据
校验和
ETX

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

Of course it will better to use OOP design.
By what you explained, I'd make at least 2 classes:

  1. Message

  2. Executer

The message will receive the command from the device, and the Executer will handle the message.

The Message object will initiate with the device's answer. It will parse it, and hold fields as you described:

STX
COMMAND
DATA
CHKSUM
ETX

Then an Executer object will receive the Message object and do the actual execution of the message, and hold the logical code.

掩于岁月 2024-10-21 11:54:27

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

  1. Command:实际上不是一个类,而是一个 Enum 值,这样您就可以检查 Command.Read 等,而不仅仅是“知道”0x01 和 0x02 的含义。
  2. 消息:只是一个普通对象(PO​​JO/POCO/其他),用于保存消息的数据表示。这将包含以下字段:
    1. Command(前面提到的枚举类型)
    2. 数据:数据列表。根据数据的表示方式,您可以为此创建一个类,也可以仅将每个数据表示为字符串。
  3. MessageParser:这将有一个函数可以解析字符串或文本流并创建 Message 对象。如果文本无效,我会抛出一个自定义异常(另一个类),该异常可以被调用者捕获。
  4. MessageExecutor:这将采用 Message 对象并执行它所代表的操作。

通过创建中间表示对象(消息),您可以分离正在执行的各种操作。例如,如果当权者决定消息文本可以作为 XML 或 JSON 发送,您可以创建不同的 MessageParser 类,而不必扰乱决定如何处理消息的逻辑。

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

I would go a step further than Yochai's answer, and create the following classes:

  1. Command: Actually not a class, but an Enum value so you can check against Command.Read, etc., rather than just "knowing" what 0x01 and 0x02 mean.
  2. Message: Just a plain object (POJO/POCO/whatever) that's intended to hold a data representation of the message. This would contain the following fields:
    1. Command (the enum type mentioned earlier)
    2. Data: List of the data. Depending on how the data is represented, you might create a class for this, or you could just represent each datum as a string.
  3. MessageParser: this would have a function that would parse a string or text stream and create a Message object. If the text is invalid, I'd throw a customized exception (another class), which can be caught by the caller.
  4. MessageExecutor: This would take a Message object and perform the action that it represents.

By making the intermediate representation object (Message), you make it possible to separate the various actions you're performing. For example, if the Powers That Be decide that the message text can be sent as XML or JSON, you can create different MessageParser classes without having to mess with the logic that decides what to do with the message.

This also makes unit testing far easier, because you can test the message parser independently of the executor. First test the message parser by calling the parse function and examining the resulting Message object. Then test the executor by creating a Message object and ensuring that the appropriate action is taken.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文