我在我的项目中负责关键的应用程序。它做一些与解析业务msgs (遗留标准),处理它们,然后将一些结果存储在DB中(另一个应用程序从中获得)相关的工作。经过一年多的工作(我还有其他的应用程序要负责),应用程序终于稳定下来了。我已经引入了严格的TDD政策,我有20%的单元测试覆盖率(谢谢Michael的书!),其中大部分都在关键部分。我也有一些白盒健身测试(包括整个业务场景)。我觉得我不能进一步重构这个应用程序,我可以安全地玩它。它设计得太差了,我想重写它。App本身就是对遗留的C/C++代码的20k左右的挑战。还有其他的依赖项,但我尽力将它们中的大部分解耦。
我只有Sun C++编译器,cppunitlite,STLPort和Boost。请不要建议其他技术(没有XML、Java等),因为在我的组织中,这不是选项。我想用现代的C++ (也许是元编程.)、TDD从头到尾完成它。
我需要解析大约30种类型的msgs。它们中的每一行都由3-10行组成,它们中的大多数是非常相似的。这是所有邪恶的->的根,大量的代码重复。每个msgs都有一个类,描述应该如何解析它。看看主继承树:
MSG_A MSG_B
/ \ / \
MSG_A_NEW MSG_A_CNL MSG_B_NEW MSG_B_CNL两棵树都要深得多。MSG_A_NEW和MSG_B_NEW之间的差异很小。它应该由单个类来处理,这些类可以注入一些小的自定义。
我最初的计划是有一个通用的msg类,它将被定制。某个实体(建筑商)..。?)将查看msgs并初始化能够解析msg的适当对象。另一个实体将能够发现它是哪一行,这个信息将被构建者使用。我计划编写几个解析器,这些解析器只负责解析一个特定的行。这将允许我在解析不同的消息时重用它。
有几个挑战,我很难以优雅和可扩展的方式解决。每种味精:
如果行有一些必须有的行有一些可选的行某些行必须在特定的位置(即日期不能在msg类型之前),则顺序重要。
我需要能够验证msgs的格式。
我不确定我在这里解释的设计挑战是否足够好。我的设计经验非常有限。我已经修复bug有一段时间了,最后我要做一些有趣的修改:)
你对此有什么高级建议?在这个描述中,您可以识别哪些设计模式?主要的设计约束是可维护性和可扩展性,性能处于底层(我们还有其他瓶颈.)。
发布于 2008-10-28 09:41:48
我建议您从包含以下常见代码的基类继承特定的消息处理类,而不是而不是:
CommonHandler
^ ^
| | = inheritance
MsgAHandler
^ ^
| |
ANewHandler ACnlHandler这种方法存在着糟糕的可重用性:例如,如果您想处理某种需要从A_NEW和A_CNL处理的消息,那么您将很快获得多重继承。
相反,我会选择一个包含公共代码的类,该类调用一个接口来自定义该公共代码。就像这样:
BasicHandler <>--- IMsgHandler ------------\
1 1 ^ ^ ^ ^ * | ^
| | | | | | = inheritance
MsgAHandler | | ANewHandler 1 |
ACnlHandler HandlerContainer <>-/ <>- = containment
The HandlerContainer class can be used to group the behaviour of other handlers together.
This pattern is called 'Composite', if I'm not mistaken. And to create the correct instances of the handlers, you will of course need some kind of factory.
Good luck!发布于 2008-10-25 21:53:41
听起来确实是个有趣的挑战。:-)
您的“初始计划”听起来不错:剔除所有消息之间的所有类似处理,并将它们的代码放在一个基本消息类中。更改的项可以成为虚拟函数(例如CheckForRequiredLines或VerifyLineOrder ),可能在最常见的情况下使用默认实现。然后派生特定消息类型的其他类。
对于这样的设计问题,很难给出一般性的建议。在我看来,您的主解析器函数似乎与Factory方法模式相对应,但这是我唯一可以轻松识别的。(我对设计模式的名称并不太熟悉--我使用了其中的许多,但我只是在几年前才知道它们的名字。)
发布于 2008-10-27 12:18:56
我建议查看boost提供的库,例如Tuple或mpl::vector。这些库允许您创建一个不相关类型的列表,然后对它们进行操作。最粗略的想法是,您对每种消息类型都有不同的类型序列:
Seq1 -> MSG_A_NEW, MSG_A_CNL
Seq2 -> MSG_B_NEW, MSG_B_CNL一旦您知道了您的消息类型,就可以使用适当的元组和函数模板,该模板将第一个元组类型应用于数据。然后是元组中的下一个条目,等等。
这确实假设您的数据流的布局是在编译时已知的,但是它的优点是您无需为数据结构支付任何运行时开销。
https://stackoverflow.com/questions/236792
复制相似问题