如何在不增加其他地方复杂性的情况下降低库的复杂性

时间:2010-02-24 16:10:44

标签: c++ design-patterns

我的任务是维护和更新一个库,该库允许计算机在硬件设备上发送命令,然后接收其响应。目前,代码的设置方式使得设备可以接收的每个可能的命令都通过其自己的功能发送。代码重复无处不在;一个干的拥护者最糟糕的噩梦。

显然,有很多改进的机会。问题是每个命令都有不同的有效负载。目前,作为有效载荷的数据以参数的形式传递给每个命令功能。如果不将复杂性推向调用库的级别,就很难整合功能。

当从设备收到响应时,其数据被放入一个专门负责保存这些数据的类的对象中,它们什么都不做。有数百个类可以做到这一点。然后,这些对象用于通过应用层访问返回的数据。

我的目标:

彻底减少代码重复

在应用层保持类似的复杂程度

更容易添加新命令

我的想法:

具有一个发送命令的功能和一个用于接收的功能(当检测到来自设备的响应时,自动调用接收功能)。有一个结构包含所有命令/响应数据,这些数据将被传递给发送函数并由接收函数返回。由于每个命令都有一个相应的枚举值,因此请使用switch语句设置任何特定于命令的数据以进行发送。

我的想法是最好的方法吗?我可以在这里使用一种设计模式吗?我看了看,但似乎没有什么能满足我的需求。

提前致谢! (如果需要澄清,请告诉我)

3 个答案:

答案 0 :(得分:2)

这让我想起了REST与SOA的争论,尽管规模较小。

如果我理解正确,那么现在你有像

这样的电话
device->DoThing();
device->DoOtherThing();

然后有时我得到像

这样的回调
callback->DoneThing(ThingResult&);
callback->DoneOtherTHing(OtherThingResult&)

我建议用户是这里的关键组件。当前库用户是否喜欢它所设计级别的界面?界面是否一致,即使它很大?

您似乎想提议

device->Do(ThingAndOtherThingParameters&)
callback->Done(ThingAndOtherThingResult&)

所以要有一个包含更复杂数据的入口点。

库用户视角的缺点可能现在我必须使用手动开关()或其他类型语句来说明实际发生的情况。虽然我已经为我调度了相应的结果回调,但现在你已经成为图书馆用户的负担了。

除非这给用户带来了某种程度的灵活性,否则我和用户希望我向后退一步。

对于您作为实现者的部分,一个建议是在内部转到通用表单,然后在外部提供两个接口。也许旧的特定的接口甚至可能以某种方式自动生成。

祝你好运。

答案 1 :(得分:1)

您的首要目标应该是创建一个库,将较高的软件层与硬件分离。您的库的用户不应该关心您是否拥有可以使用不同的有效负载执行许多功能的硬件设备。他们应该只关心设备在更高层次上的作用。从这个意义上说,在我看来,每个命令都映射到每个函数都是一件好事。

我的计划是:

  • 确定更高数据层完成工作所需的对象。从他们的角度为C ++类中的对象建模,而不是从硬件的角度来看
  • 使用上述对象
  • 定义库的界面
  • 开始实施该库。可能需要将软件对象映射到硬件对象的中间层
  • 您可以采取许多措施来减少代码重复。你可以使用多态。使用基本功能定义一个类并对其进行扩展。您还可以使用实用程序类来实现许多命令所需的功能。

答案 2 :(得分:1)

嗯,你的问题意味着图书馆的复杂性和客户端之间存在平衡。当这些是唯一的两个选择时,几乎总是会让客户的生活更轻松。然而,这些很少是真正的两个选择。

现在在本文中,您将讨论命令处理架构,其中每个命令都有一组与之关联的不同数据。在过去,这通常会在循环中使用大喇叭case语句来实现,其中每个案例都使用不同的参数调用不同的例程,也许还有一些设置代码。可怕的。 McCabe复杂性分析师讨厌这个。

现在,您可以使用OO语言执行使用动态调度。使用标准的“handle()”方法创建一个基本抽象“命令”类,并让每个不同的命令继承它以添加自己的成员(以表示不同命令的不同“参数”)。然后在启动时创建一个大的鸣喇叭数组,通常由命令ID索引。对于像C ++或Ada这样的语言,它必须是指向“命令”对象的指针数组,才能使动态调度工作。然后,您可以为从客户端读取的命令ID调用相应的命令对象。现在,动态调度隐式处理了大喇叭case语句。

在这种情况下你可以获得大笔节省的是子类化。你有几个使用完全相同参数的命令吗?为它们创建一个子类,然后从该子类派生所有这些命令。您是否有几个命令必须对其中一个参数执行相同的操作?使用为该操作实现的一个方法为它们创建一个子类,然后从该子类派生所有这些命令。