加载多种消息类型的设计模式 [英] Design pattern for loading multiple message types

查看:40
本文介绍了加载多种消息类型的设计模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我浏览 SO 时,我遇到了一个关于 处理多条消息的问题类型.我担心的是 - 如何以简洁的方式加载这样的消息?我决定有一个单独的类,它的方法是每次调用时加载一条消息.此方法应该创建一个具体消息类型的新实例(例如 AlphaMessage、BetaMessage、GammaMessage 等)并将其作为 Message 返回.

As I was looking through SO I came across a question about handling multiple message types. My concern is - how do I load such a message in a neat way? I decided to have a separate class with a method which loads one message each time it's invoked. This method should create a new instance of a concrete message type (say AlphaMessage, BetaMessage, GammaMessage, etc.) and return it as a Message.

class MessageLoader
{
    public Message Load()
    {
        // ...
    }
}

方法中的代码对我来说看起来非常糟糕,我非常想重构它/摆脱它:

The code inside the method is something which looks really awful to me and I would very much like to refactor it/get rid of it:

Message msg = Message.Load(...); // load yourself from whatever source
if (msg.Type == MessageType.Alpha) return new AlphaMessage(msg);
if (msg.Type == MessageType.Beta) return new BetaMessage(msg);
// ...

事实上,如果整个设计看起来太乱,而你们有更好的解决方案,我已经准备好重组整个设计.

In fact, if the whole design looks just too messy and you guys have a better solution, I'm ready to restructure the whole thing.

如果我的描述太混乱,请让我知道它缺少什么,我将编辑问题.谢谢大家.

If my description is too chaotic, please let me know what it's missing and I shall edit the question. Thank you all.

我不喜欢这段代码的是我必须创建一个 Message 的实例(因为它知道如何加载自己)然后必须用具体的消息类型来装饰它(因为装饰器知道如何解释 msg 的 Data 属性).也许这会使问题更清楚一些.

What I don't like about this code is that I have to create an instance of a Message (cause it knows how to load itself) and then have to decorate it with a concrete message type (cause decorators know how to interpret msg's Data property). Maybe this will make the question slightly more clear.

推荐答案

下一级抽象是使消息发现和实例化动态化.这通常通过将字符串名称与每个消息相关联或使用类的名称作为标识符来实现.您可以使用反射来发现可用的消息类型,将它们存储在字典中并按名称提供实例化.这可以进一步扩展以从动态加载的插件"程序集中引入消息,具有适当的元数据和接口,以允许不同消息和消息消费者之间的松散耦合组合.一旦达到该级别,我建议您查看诸如 MEF 之类的框架,它们可以自动执行发现和实例注入过程.

The next level of abstraction is to make Message discovery and instantiation dynamic. This is often accomplished by associating a string name with each Message or by using the name of the class as an identifier. You can use Reflection to discover available Message types, store them in a Dictionary and provide instantiation by name. This can be further extended to bring in Messages from dynamically loaded 'plugin' assemblies, with appropriate meta-data and interfaces to allow for loosely coupled composition between different Messages and Message Consumers. Once you get to that level, I recommend looking into frameworks like MEF which automate the discovery and instance injection process.

对于您的简单应用程序,我认为您的方法已经很干净了.一系列 if 语句或 switch 工作得很好,并且很容易理解/维护,只要你有一个相对较小和稳定的案例集.

For your simple application, I think your approach is already quite clean. A series of if statements or a switch works just fine and is easy to understand/maintain, as long as you have a relatively small and stable set of cases.

总结评论中的进一步讨论:

Summarizing the further discussion in the comments:

引起不安的主要设计问题是,从 Message 继承的不同特定消息和基本 Message 必须先实例化,然后才能对更具体的消息进行进一步分析.这混淆了 Message 是打算包含原始信息还是充当解释消息的基本类型.更好的设计是将 RawMessage 功能分离到自己的类中,清楚地分离关注点并解决实例化两次"的感觉.

The main design concern creating uneasiness was the fact that the different specific messages inherited from Message and yet a base Message had to be instantiated before the more specific messages could perform further analysis. This muddied up whether the Message is intended to contain raw information or to act as a base type for interpreted messages. A better design is to separate the RawMessage functionality into its own class, clearly separating concerns and resolving the feeling of 'instantiating twice'.

至于使用 DTO 和映射器类进行重构:

As for refactoring with DTOs and a mapper class:

实际上,我更喜欢您针对特定于应用程序的消息编码/解码的方法.如果我想找出 FactoryTakenOverByRobotsMessage 包含无效数据的原因,那么消息的解析器方法包含在消息的解码数据中对我来说是有意义的.如果您想要支持不同的编码,事情会变得更加危险,因为现在您开始想要以声明方式(例如使用属性)指定 DTO,并允许不同的传输层决定如何序列化/反序列化.但是,在我使用您的模式的大多数情况下,它是针对特定于应用程序的情况,通常有些不一致的消息格式和各种无法以任何自动方式很好地映射的专有编码.我仍然可以始终将声明性编码与专有的类内编码并行使用,并执行诸如将我的消息序列化为 XML 以进行调试之类的操作.

I actually prefer your approach for an app-specific message encoding/decoding. If I want to track down why FactoryTakenOverByRobotsMessage contains invalid data, it makes sense to me that the parser method for the message is contained with the decoded data for the message. Where things get more dicey if when you want to support different encodings, as now you start wanting to specify the DTO declaratively (such as with attributes) and allow your different transport layers to decide how to serialize/deserialize. In most cases where I'm using your pattern, however, it's for a very app-specific case, with often somewhat inconsistent message formats and various proprietary encodings that don't map well in any automatic way. I can always still use the declarative encoding in parallel with the proprietary, in-class encoding and do things like serialize my messages to XML for debugging purposes.

这篇关于加载多种消息类型的设计模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆