2010-02-24 81 views
2

我的任务是维护和更新一个库,它允许计算机在硬件设备上发送命令,然后接收其响应。目前代码的设置方式是设备可以接收的每个可能的命令都是通过自己的功能发送的。代码重复无处不在; DRY倡导者最糟糕的噩梦。如何在不增加其他地方的复杂性的情况下降低库中的复杂度?

显然有很多改进的机会。问题是每个命令有不同的有效载荷。目前,要作为有效载荷的数据以参数的形式传递给每个命令函数。如果不将复杂性推到一个称为图书馆的水平,就很难合并功能。

当收到来自设备的响应时,其数据被放入一个完全负责保存这些数据的类的对象中,但它们什么也不做。有数百个这样做的课程。这些对象随后用于通过应用层访问返回的数据。

我的目标:

Throughly减少代码的重复

维持在应用层

复杂的similiar水平更轻松地添加新的命令

我的想法:

有无一个函数发送一个命令,另一个接收函数(接收函数在响应时自动调用检测到来自设备的电子邮件)。有一个结构体,它保存所有将被传递给发送函数并由接收函数返回的命令/响应数据。由于每个命令都有相应的枚举值,因此需要一个switch语句来设置用于发送的任何命令特定数据。

我的想法是最好的办法吗?有我可以在这里使用的设计模式吗?我看了看,但看起来并不符合我的需求。

在此先感谢! (如果需要澄清,请让我知道)

回答

1

那么,你的问题意味着图书馆的复杂性和客户之间存在一个平衡点。当这些只有两种选择时,几乎总是会让客户的生活更轻松。但是,这些并不是真正的唯一选择。

现在在文中您将讨论一个命令处理架构,其中每个命令都有一组与其相关的不同数据。在过去的日子里,这通常会在循环中用一个大声的鸣叫case来实现,其中每种情况都称不同的例程具有不同的参数,并且可能有一些设置代码。可怕的。 McCabe复杂性分析仪讨厌这一点。

这些天你可以用面向对象语言做什么是使用动态调度。用一个标准的“handle()”方法创建一个基本的抽象“命令”类,并让每个不同的命令从它继承来添加它们自己的成员(以表示不同命令的不同“参数”)。然后在启动时创建一个大的喇叭阵列,通常由命令ID进行索引。对于像C++或Ada这样的语言,它必须是一个指向“命令”对象的指针数组,以便动态分派工作。然后,您可以调用适当的命令对象来获取从客户端读取的命令ID。现在大声疾呼的case声明由动态调度隐式处理。

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

+0

感谢您的输入。我绝对同意,无论我最终做什么,我都不想增加客户的复杂性。你所描述的古代所用的方法与我所提出的方法很接近。 case语句将用于设置发送到设备的有效负载。 您的设备调度想法是我一直在考虑的事情。我不一定喜欢大喇叭阵列的想法(设置可能很麻烦),但是看起来我最终会得到一个大鸣喇叭的SOMETHING,无论我的方法如何。 – Hojdra 2010-02-24 19:17:13

+0

您实际上可以通过旧式'case'调度方法获得一些代码共享...但它涉及到使用goto。这不是大多数人想要(甚至应该)做的事情。 – 2010-02-24 20:02:54

+0

哈哈,不,我宁愿不要被迪克斯特拉的鬼魂困扰:)。我一直在想你的建议。正如你所说,我目前的想法是,每个从基类继承的命令都有一个类。每个类都有一个SendCommand和HandleResponse方法。该类还将封装发送该命令所需的所有数据以及响应该命令而收到的任何数据。该库已经使用函数映射来决定在收到响应时要调用哪个响应函数,因此不会有太大的变化。 – Hojdra 2010-02-24 20:14:35

2

这让我想起了REST vs. SOA的争论,尽管体型较小。

如果我理解正确的话,现在你有一个像

device->DoThing(); 
device->DoOtherThing(); 

电话,然后有的时候我喜欢

callback->DoneThing(ThingResult&); 
callback->DoneOtherTHing(OtherThingResult&) 

一个回调,我建议用户是关键部件在这里。目前的图书馆用户是否喜欢它所设计级别的界面?界面是否一致,即使它很大?

你似乎想提出

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

所以有更复杂的数据单入口点。

从库用户角度来看缺点可能现在我不得不使用手动switch()或其他类型的语句来告诉真正发生了什么。虽然调度到适当的结果回调过去是为我完成的,但现在你已经使它成为图书馆用户的负担。

除非这给我买了一定程度的灵活性,那我想用户想要我会考虑这个倒退一步。

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

祝你好运。

+0

谢谢您的输入。你对我的主张的解释是正确的。但是,用户不必处理回调。用户可以使用“Do”方法将指针传递给结构体,然后通过从设备收到响应时调用该方法来填充指针。我的观点是有人需要向图书馆添加新的命令,并发现目前的体系结构很困难和令人沮丧。不过,我认为你是正确的,我需要首先考虑用户的视角。单独的命令功能更加明确。 – Hojdra 2010-02-24 17:51:54

1

您的第一个目标应该是生成一个将较高软件层与硬件分离的库。你的库的用户不应该在意你有一个硬件设备可以用不同的有效载荷执行许多功能。他们应该只关心设备在更高级别上的功能。从这个意义上说,我认为每一个命令都映射到每一个函数是一件好事。

我的计划是:

  • 确定更高的数据层需要完成工作的对象。从他们的角度而不是从硬件角度对C++类中的对象进行建模
  • 使用上述对象定义库的接口
  • 开始库的实现。可能需要将软件对象映射到硬件对象的中间层
  • 您可以通过很多事情来减少代码重复。你可以使用多态。定义一个具有基本功能的类并对其进行扩展。您也可以使用实用程序类,实现许多命令所需的功能。
+0

感谢您的输入。好吧,我想我应该更清楚这一点,这个库的许多用例包括在某些情况下测试设备,以便用户需要查看设备是否正确响应命令。在这种情况下,他们确实需要将其视为执行命令的硬件设备。我完全可以看到将每个命令映射到单独函数的优点。我喜欢你的中间层的想法。我可能会保留当前可用的接口,并将数据映射到一个新的,组织更好的命令有效负载设置。 – Hojdra 2010-02-24 18:56:11