防止滥用专为运输而设计的结构
我开发的产品有多个组件,其中大部分是用 C++ 编写的,但有一个是用 C 编写的。我们经常遇到这样的场景:一条信息通过 IPC 流经每个组件。
我们使用结构体定义这些消息,以便将它们打包到消息中并通过消息队列发送它们。这些结构仅设计用于“传输”目的,并且以仅服务于该目的的方式编写。我遇到的问题是:程序员保留该结构并将其用作信息的长期容器。
在我看来,这是一个问题,因为:
1)如果我们更改传输结构,那么它们的所有代码都会被破坏。这里应该进行封装,这样我们就不会遇到这种情况。
2)消息结构非常尴尬,并且仅设计用于传输信息...该结构似乎不太可能恰好是这些其他组件访问此数据(长期)的最方便形式。
我的问题是:如何以编程方式防止这种误用?我想强制要求这些结构只能用于运输。
编辑:我将尽力在这里提供一个示例:
struct smallElement {
int id;
int basicFoo;
};
struct mediumElement {
int id;
int basicBar;
int numSmallElements;
struct smallElement smallElements[MAX_NUM_SMALL];
};
struct largeElement {
int id;
int basicBaz;
int numMediumElements;
struct mediumElement[MAX_NUM_MEDIUM];
};
效果是人们只是保留“largeElement”,而不是从largeElement中提取他们需要的数据并将其放入满足他们需求的类中。
I work on a product which has multiple components, most of them are written in C++ but one is written in C. We often have scenarios where a piece of information flows through each of the components via IPC.
We define these messages using structs so we can pack them into messages and send them over a message queue. These structs are designed for 'transport' purposes only and are written in a way that serves only that purpose. The problem I'm running into is this: programmers are holding onto the struct and using it as a long-term container for the information.
In my eyes this is a problem because:
1) If we change the transport structure, all of their code is broken. There should be encapsulation here so that we don't run into this scenario.
2) The message structs are very awkward and are designed only to transport the information...It seems highly unlikely that this struct would also happen to be the most convenient form of accessing this data (long term) for these other components.
My question is: How can I programmatically prevent this mis-usage? I'd like to enforce that these structures are only able to be used for transport.
EDIT: I'll try to provide an example here the best I can:
struct smallElement {
int id;
int basicFoo;
};
struct mediumElement {
int id;
int basicBar;
int numSmallElements;
struct smallElement smallElements[MAX_NUM_SMALL];
};
struct largeElement {
int id;
int basicBaz;
int numMediumElements;
struct mediumElement[MAX_NUM_MEDIUM];
};
The effect is that people just hold on to 'largeElement' rather than extracting the data they need from largeElement and putting it into a class which meets their needs.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当我定义消息结构(在 C++ 中,在 C 中无效)时,我确保:
我不确定消息是否仍然是 Pod,但我想从内存的角度来看这是等效的。
要实现这一目标,需要做的事情:
例如,您可以拥有这个:
那么您应该拥有这个:
现在,用户将能够构建消息,以从中读取,但不会长时间更改它,从而使其无法用作数据容器。然而,他们可以存储一条消息,但以后无法更改它,因此它仅对记忆有用。
或者....您可以使用“黑匣子”。
这样,用户就无法使用结构作为数据容器,因为它们没有自己的定义。他们只能访问数据。
这样做有两个问题:明显的性能成本,并且编写和更改显然更繁重。也许使用一些代码生成器会更好。 Google Protobuf 在这个领域充满了好主意。
但最好的方法是让他们明白为什么他们的做法迟早会被打破。
When I define message structures (in C++, not valid in C ) I make sure that :
I'm not sure if the messages will still be pods but I guess it's equivalent from the memory point of view.
The things to do to achieve this :
For example you could have this :
Then you should have this :
Now, the users will be able to build the message, to read from it, but not change it in the long way, making it unusable as a data container. They could however store one message but will not be able to change it later so it's only useful for memory.
OR.... You could use a "black box".
That way, the users just cant use the structs as data containers, because they dont have their definitions. they conly can access the data.
There a two problems with this : obvious performance cost and it's clearly heavier to write and change. Maybe using some code generator would be better. Google Protobuf is full of good ideas in this domain.
But the best way would be to make them understand why their way of doing will break soon or later.
程序员这样做是因为这是获得他们想要的功能的最简单的途径,阻力最小。如果数据位于具有适当访问器的类中,他们可能会更容易访问数据,但随后他们必须编写该类并编写转换函数。
利用他们的懒惰,为他们制定最简单的道路,做正确的事。对于您创建的每个消息结构,创建一个相应的类,使用带有转换方法的良好接口来存储和访问数据,使其成为将消息放入类中的一个行。由于该类将具有更好的访问器方法,因此他们使用它比做错误的事情更容易。例如:
与其想方设法强迫他们不走捷径,不如让他们以最简单的方式使用代码。事实上,多个程序员正在使用这种反模式,这让我认为库中缺少一个应该由库提供来适应这一点的部分。您正在将这个必要组件的创建推回到代码的用户身上,并且不喜欢他们提出的解决方案。
The programmers are doing this because its the easiest path of least resistance to getting the functionality they want. It may be easier for them to access the data if it were in a class with proper accessors, but then they'd have to write that class and write conversion functions.
Take advantage of their laziness and make the easiest path for them be to do the right thing. For each message struct you creat, create a corresponding class for storing and accessing the data using a nice interface with conversion methods to make it a one liner for them to put the message into the class. Since the class would have nicer accessor methods, it would be easier for them to use it than to do the wrong thing. eg:
Rather than find ways to force them to not take the easy way out, make the way you want them to use the code the easiest way. The fact that multiple programmers are using this antipattern, makes me think there is a piece missing to the library that should be provided by the library to accomodate this. You are pushing the creation of this necessary component back on the users of the code, and not likeing the solutions they come up with.
您可以根据 const 引用来实现它们,以便服务器端构造传输结构,但客户端使用只允许对它们进行 const 引用,并且不能实际实例化或构造它们来强制执行您想要的用法。
不幸的是,如果没有您的消息、打包、正确用法和不正确用法的代码片段,我无法真正提供有关如何在您的情况下实现此功能的更多详细信息,但我们在数据模型中使用类似的内容来防止不当使用。我还导出并提供模板存储类,以减轻客户端在确实想要存储检索到的数据时使用的消息的数量。
You could implement them in terms of const references so that server side constructs the transport struct but client usage is only allowed to have const references to them and can't actually instantiate or construct them to enforce the usage you want.
Unfortunately without a code snippets of your messages, packaging, correct usage, and incorrect usage I can't really provide more detail on how to implement this in your situation but we use something similar in our data model to prevent improper usage. I also export and provide template storage classes to ease the population from the message for client usage when they do want to store the retrieved data.
通常将传输消息定义为结构是一个坏主意。最好为其定义“正常”(对程序员有用)结构和序列化器/反序列化器。为了自动化序列化器/反序列化器编码,可以在单独的文件中使用宏定义结构,并自动生成 typedef 结构和序列化器/反序列化器(增强预处理器库也可能有帮助)
usually there is a bad idea to define transport messages as structures. It's better to define "normal" (useful for programmer) struct and serializer/deserializer for it. To automate serializer/deserializer coding it's possible to define structure with macroses in a separate file and generate typedef struct and serializer/deserializer automatically(boost preprocessor llibrary may also help)
我不能说比这更简单:使用协议缓冲区。从长远来看,它会让你的生活变得更加轻松。
i can't say it more simple than this: use protocol buffers. it will make your life so much easier in the long run.