I'm tasked with implementing a messaging system for a real-time simulation. There are several different kinds of messaging objects that need to exist in this system, and more might be added in the future. These objects represent the primary means of communication between the players in the sim. Assuming I fully understand my requirements, the messaging objects can be defined by the following attributes:
我的任务是实现用于实时模拟的消息传递系统。此系统中需要存在多种不同类型的消息传递对象,将来可能会添加更多消息传递对象。这些对象代表了sim中玩家之间的主要通信方式。假设我完全理解我的要求,可以通过以下属性定义消息传递对象:
- Send protocol (what messages a player can send and when)
- Receive protocol (what messages a player can receive and how often)
- Message format (structure of the data being sent)
发送协议(播放器可以发送什么消息以及何时发送)
接收协议(播放器可以接收哪些消息以及频率)
消息格式(正在发送的数据的结构)
The simulation code currently only supports one send and receive protocol and one message format. My job is to make the code more extensible so it can support future changes/additions to protocols and message structure. A first-cut approach to this would be to define abstract base classes for each of the attributes and have each messaging object be composed of handles to them. Every messaging object can then be written as different combinations of protocol and format objects. My concern is that this design can quickly become over-generalized and thus a maintenance nightmare. I cringe at the thought of sifting through a dozen files just to figure out how the heck a FooMessaging
really works.
模拟代码目前仅支持一种发送和接收协议以及一种消息格式。我的工作是使代码更具可扩展性,以便它可以支持将来对协议和消息结构的更改/添加。对此的第一个方法是为每个属性定义抽象基类,并让每个消息传递对象由它们的句柄组成。然后可以将每个消息传递对象写为协议和格式对象的不同组合。我担心的是,这种设计很快就会过度概括,从而成为维护的噩梦。我想通过十几个文件进行筛选只是为了弄清楚FooMessaging是如何工作的。
I'll be writing this in C++, but I think this is really more a general design question. Are there any "standard" patterns or best practices I can apply here?
我将用C ++编写这个,但我认为这更像是一个通用的设计问题。我可以在这里申请任何“标准”模式或最佳实践吗?
2 个解决方案
#1
Okay, I suspect you're doing an A to Z process starting at about G.
好的,我怀疑你正在从大约G开始进行A到Z的过程。
First of all, what are your use cases? What are you trying to do? What kind of "messaging system" are you building? EMAIL? IM? Telepathic?
首先,你的用例是什么?你想做什么?您正在构建什么样的“消息系统”?电子邮件? IM?心灵感应?
Second, what is the domain that you get from those use cases?
其次,您从这些用例中获得的域名是什么?
Now, having thought that through, then yes, you often find it convenient to make an ABC for the basic classes. Consider making an interface instead (although the distinction between interfaces and ABCs in C++ is less well defined than other languages.) Over the last 20 years, inheritance-based OO has turned out to impose a lot of problems, so that interfaces and aggregation are now favored. Not always better, but you should think of them first.
现在,考虑到通过,然后是的,你经常发现为基本类制作ABC很方便。考虑改为创建一个接口(尽管C ++中的接口和ABCs之间的区别比其他语言的定义要差。)在过去的20年中,基于继承的OO已经证明存在很多问题,因此接口和聚合都是现在很受欢迎。并不总是更好,但你应该先考虑它们。
Now, tell me what the physical thing corresponding to the "protocol" is? Do you mean to model something like a message stream? Is it a communications medium?
现在,告诉我“协议”对应的物理内容是什么?你的意思是建模消息流吗?它是一种通讯媒介吗?
Format in particular sounds suspicious, if not immediately wrong: message formats tend to be tied intimately to the protocol.
特别是格式听起来很可疑,如果不是立即错误的话:消息格式往往与协议密切相关。
Basically, back up a bit and tell us more about what you're trying to do, first.
基本上,先备份一下,然后告诉我们更多关于你要做什么的事情。
Update
Aha. Okay, see, we get a lot of help from this. First, you mean "protocol" in the sense of the available operations — a perfectly reasonable usage, but confusing when you confound it with TCP vs UDP, that sort of thing, as I did.
啊哈。好的,看,我们从中获得了很多帮助。首先,你指的是可用操作意义上的“协议” - 一个完全合理的用法,但是当你把它与TCP和UDP混淆时会让人感到困惑,就像我做的那样。
Now, that said, you do indeed have a couple of options at least. In the following, I use the term "Player" for any entity in the sim that can send or receive messages.
现在,那说,你确实至少有几个选择。在下文中,我对SIM中可以发送或接收消息的任何实体使用术语“播放器”。
The key notion here is to design around the loci for change, and around nonfunctional requirements. The obvious loci of change are
这里的关键概念是围绕基因座进行设计以进行更改,并围绕非功能性需求进行设计。明显的变化轨迹是
-
you can have several "protocols" in your sense, and if you have as many as three, you should just plan that there can always be more. If you expect more than two, plan that you can have arbitrarily many.
你可以在你的意义上有几个“协议”,如果你有多达三个,你应该计划总有更多。如果您期望超过两个,请计划您可以任意多次。
-
you can have several different ways of formatting messages, ie, JSON, XML, or YAML, say. AGain, if you expect more than two, plan that you can have arbitrarily many.
你可以有几种不同的格式化消息的方法,比如JSON,XML或YAML。如果你期望超过两个,那么AGain计划你可以任意多。
-
You can have several transport mechanisms. From the sounds of things, you can at least use UNIX-domain sockets×shared memory×named pipes, but then my intuition says you also have the option of local and remote, which means you also have the option of UDP or TCP. Definitely more than two, plan for extensibility.
您可以拥有多种传输机制。从事物的声音来看,你至少可以使用UNIX域套接字×共享内存×命名管道,但是我的直觉说你也可以选择本地和远程,这意味着你也可以选择UDP或TCP。绝对超过两个,计划可扩展性。
Use a Proxy pattern, where each protocol defines an interface that must be implemented in one of several ways, depending upon the messaging format underneath. Players advertise what messages they're willing to receive; at the time they are prepared to receive a message, they construct something that invokes their code for any specific operation message they receive. To send, they construct an object implementing the appropriate interface for their receiving partner Player.
使用代理模式,其中每个协议定义一个必须以多种方式之一实现的接口,具体取决于下面的消息传递格式。玩家宣传他们愿意接收的消息;在他们准备接收消息时,他们构造一些东西,为他们收到的任何特定操作消息调用他们的代码。要发送,他们构造一个对象,为其接收伙伴Player实现适当的接口。
Under the covers, these objects can have several realizations, each for a different messaging format and transport mechanism.
在幕后,这些对象可以有多个实现,每个实现用于不同的消息传递格式和传输机制。
Examples of a system like this include SOM/DSOM a/k/a CORBA, and Java RMI using the Remote interface.
像这样的系统的示例包括SOM / DSOM a / k / a CORBA和使用Remote接口的Java RMI。
Option 2:You can build something around the Command pattern. Each protocol has a specific implementation of "send me", and your receiver simply knows how to reconstruct an object sent. The command objects have a mix-in (multiply-inherited, or passed as an object at run time) that knows how to marshall and serialize the Command object; you can have a second one that understands the transport mechanism.
您可以围绕Command模式构建一些东西。每个协议都有一个“发送给我”的具体实现,你的接收器只知道如何重建发送的对象。命令对象具有混合(多次继承,或在运行时作为对象传递),它知道如何编组和序列化Command对象;你可以有第二个了解运输机制的人。
You send a message on a particular protocol by serializing the object and using your transport mechanism to move the serialized form to the receiver. The receiver "rehydrates" the object, and invokes the appropriate methods based on the actual type sent.
通过序列化对象并使用传输机制将序列化表单移动到接收器,您可以在特定协议上发送消息。接收器“重新水化”对象,并根据发送的实际类型调用适当的方法。
An example of this is Java RMI with the Serializable interface instead of using Remote.
这方面的一个例子是带有Serializable接口的Java RMI,而不是使用Remote。
#2
I believe you should take a look on Apache ActiveMQ. Actually, it is written on Java, but has option to use C++ clients and well documented also.
我相信你应该看看Apache ActiveMQ。实际上,它是用Java编写的,但可以选择使用C ++客户端,也有很好的文档。
Cheers.
#1
Okay, I suspect you're doing an A to Z process starting at about G.
好的,我怀疑你正在从大约G开始进行A到Z的过程。
First of all, what are your use cases? What are you trying to do? What kind of "messaging system" are you building? EMAIL? IM? Telepathic?
首先,你的用例是什么?你想做什么?您正在构建什么样的“消息系统”?电子邮件? IM?心灵感应?
Second, what is the domain that you get from those use cases?
其次,您从这些用例中获得的域名是什么?
Now, having thought that through, then yes, you often find it convenient to make an ABC for the basic classes. Consider making an interface instead (although the distinction between interfaces and ABCs in C++ is less well defined than other languages.) Over the last 20 years, inheritance-based OO has turned out to impose a lot of problems, so that interfaces and aggregation are now favored. Not always better, but you should think of them first.
现在,考虑到通过,然后是的,你经常发现为基本类制作ABC很方便。考虑改为创建一个接口(尽管C ++中的接口和ABCs之间的区别比其他语言的定义要差。)在过去的20年中,基于继承的OO已经证明存在很多问题,因此接口和聚合都是现在很受欢迎。并不总是更好,但你应该先考虑它们。
Now, tell me what the physical thing corresponding to the "protocol" is? Do you mean to model something like a message stream? Is it a communications medium?
现在,告诉我“协议”对应的物理内容是什么?你的意思是建模消息流吗?它是一种通讯媒介吗?
Format in particular sounds suspicious, if not immediately wrong: message formats tend to be tied intimately to the protocol.
特别是格式听起来很可疑,如果不是立即错误的话:消息格式往往与协议密切相关。
Basically, back up a bit and tell us more about what you're trying to do, first.
基本上,先备份一下,然后告诉我们更多关于你要做什么的事情。
Update
Aha. Okay, see, we get a lot of help from this. First, you mean "protocol" in the sense of the available operations — a perfectly reasonable usage, but confusing when you confound it with TCP vs UDP, that sort of thing, as I did.
啊哈。好的,看,我们从中获得了很多帮助。首先,你指的是可用操作意义上的“协议” - 一个完全合理的用法,但是当你把它与TCP和UDP混淆时会让人感到困惑,就像我做的那样。
Now, that said, you do indeed have a couple of options at least. In the following, I use the term "Player" for any entity in the sim that can send or receive messages.
现在,那说,你确实至少有几个选择。在下文中,我对SIM中可以发送或接收消息的任何实体使用术语“播放器”。
The key notion here is to design around the loci for change, and around nonfunctional requirements. The obvious loci of change are
这里的关键概念是围绕基因座进行设计以进行更改,并围绕非功能性需求进行设计。明显的变化轨迹是
-
you can have several "protocols" in your sense, and if you have as many as three, you should just plan that there can always be more. If you expect more than two, plan that you can have arbitrarily many.
你可以在你的意义上有几个“协议”,如果你有多达三个,你应该计划总有更多。如果您期望超过两个,请计划您可以任意多次。
-
you can have several different ways of formatting messages, ie, JSON, XML, or YAML, say. AGain, if you expect more than two, plan that you can have arbitrarily many.
你可以有几种不同的格式化消息的方法,比如JSON,XML或YAML。如果你期望超过两个,那么AGain计划你可以任意多。
-
You can have several transport mechanisms. From the sounds of things, you can at least use UNIX-domain sockets×shared memory×named pipes, but then my intuition says you also have the option of local and remote, which means you also have the option of UDP or TCP. Definitely more than two, plan for extensibility.
您可以拥有多种传输机制。从事物的声音来看,你至少可以使用UNIX域套接字×共享内存×命名管道,但是我的直觉说你也可以选择本地和远程,这意味着你也可以选择UDP或TCP。绝对超过两个,计划可扩展性。
Use a Proxy pattern, where each protocol defines an interface that must be implemented in one of several ways, depending upon the messaging format underneath. Players advertise what messages they're willing to receive; at the time they are prepared to receive a message, they construct something that invokes their code for any specific operation message they receive. To send, they construct an object implementing the appropriate interface for their receiving partner Player.
使用代理模式,其中每个协议定义一个必须以多种方式之一实现的接口,具体取决于下面的消息传递格式。玩家宣传他们愿意接收的消息;在他们准备接收消息时,他们构造一些东西,为他们收到的任何特定操作消息调用他们的代码。要发送,他们构造一个对象,为其接收伙伴Player实现适当的接口。
Under the covers, these objects can have several realizations, each for a different messaging format and transport mechanism.
在幕后,这些对象可以有多个实现,每个实现用于不同的消息传递格式和传输机制。
Examples of a system like this include SOM/DSOM a/k/a CORBA, and Java RMI using the Remote interface.
像这样的系统的示例包括SOM / DSOM a / k / a CORBA和使用Remote接口的Java RMI。
Option 2:You can build something around the Command pattern. Each protocol has a specific implementation of "send me", and your receiver simply knows how to reconstruct an object sent. The command objects have a mix-in (multiply-inherited, or passed as an object at run time) that knows how to marshall and serialize the Command object; you can have a second one that understands the transport mechanism.
您可以围绕Command模式构建一些东西。每个协议都有一个“发送给我”的具体实现,你的接收器只知道如何重建发送的对象。命令对象具有混合(多次继承,或在运行时作为对象传递),它知道如何编组和序列化Command对象;你可以有第二个了解运输机制的人。
You send a message on a particular protocol by serializing the object and using your transport mechanism to move the serialized form to the receiver. The receiver "rehydrates" the object, and invokes the appropriate methods based on the actual type sent.
通过序列化对象并使用传输机制将序列化表单移动到接收器,您可以在特定协议上发送消息。接收器“重新水化”对象,并根据发送的实际类型调用适当的方法。
An example of this is Java RMI with the Serializable interface instead of using Remote.
这方面的一个例子是带有Serializable接口的Java RMI,而不是使用Remote。
#2
I believe you should take a look on Apache ActiveMQ. Actually, it is written on Java, but has option to use C++ clients and well documented also.
我相信你应该看看Apache ActiveMQ。实际上,它是用Java编写的,但可以选择使用C ++客户端,也有很好的文档。
Cheers.