哪个更好:一堆吸气剂或带有选择字符串参数的1个方法?


15

我们的知识领域涉及人们赤脚行走在压力记录板上。如果在传感器数据中识别出人脚,我们会进行图像识别,从而产生“脚”类对象。

必须对脚的数据执行一些计算。

现在,哪种API更好:

class Foot : public RecognizedObject  { 
  MaxPressureFrame getMaxPressureFrame();
  FootAxis getFootAxis();
  AnatomicalZones getAnatomicalZones();

  // + similar getters for other calculations

  // ...
}

要么:

class Foot : public RecognizedObject {
  virtual CalculationBase getCalculation(QString aName);

  // ...
}

现在,我可以提出很多优点和缺点,但是我不能真正决定哪个最重要。请注意,这是最终用户应用程序,而不是我们出售的软件库。

有什么建议吗?

第一种方法的一些专家可能是:

  • 吻-一切都非常具体。API,但实施也是如此。
  • 强类型返回值。
  • 从此类继承是万无一失的。什么都不能覆盖,只能添加。
  • API是非常封闭的,什么都不会进入,什么都不能被覆盖,所以更少的地方会出错。

一些缺点:

  • 随着我们发明的每一项新计算都被添加到列表中,吸气剂的数量将会增加
  • API更可能会更改,如果引入了重大更改,我们需要一个新的API版本,即Foot2。
  • 如果在其他项目中重复使用该类,我们可能不需要进行所有计算

第二种方法有些专业人士:

  • 更灵活
  • api更改的可能性较小,(假设我们正确提取了抽象,如果不正确,更改将花费更多)

一些缺点:

  • 松散类型。每次通话都需要转换。
  • 字符串参数-我对此有不好的感觉(分支字符串值...)
  • 当前没有用例/需求要求额外的灵活性,但将来可能会存在。
  • API施加了限制:每次计算都需要从基类派生。除非通过一种更动态,更灵活的方式来传递参数,否则将无法通过这种1方法来进行计算,而且传递额外的参数将是不可能的,这将进一步增加复杂性。

5
您可以制作一个enum并打开其值。不过,我认为第二种选择是邪恶的,因为它偏离了KISS。
Vorac 2014年

如果使用字符串参数来触发特定计算,则很难找到它的所有用法。很难成为100%,您找到了所有这些。
Konrad Morawski 2014年

充分利用两个世界的优势,编写带有许多吸气剂的外观getCalculation()
2014年

1
枚举绝对比字符串好!我没有想到这一点。它们限制了API并防止了字符串参数的滥用(例如令牌和其他废话的连接),所以我猜比较是使用枚举而不是字符串的选项1和选项2之间的比较。
Bgie 2014年

Answers:


6

我认为第一种方法会有所收获。魔术字符串可能会产生以下问题:键入错误,滥用,返回类型的安全性不佳,代码完成不足,代码不清晰(此版本具有该功能吗?我想我们会在运行时找到)。使用枚举可以解决其中的一些问题,但让我们看一下您提出的缺点:

  • 随着我们发明的每一项新计算都被添加到列表中,吸气剂的数量将会增加

没错,这可能很烦人,但是它使事情变得更加严格和严格,并且可以在任何现代IDE中的项目中的任何地方为您提供代码完成功能,并且标题注释比枚举要有用得多。

  • API更可能会更改,如果引入了重大更改,我们需要一个新的API版本,即Foot2。

是的,但这实际上是一个强大的专业;),您可以为部分API定义接口,然后无需重新编译不受较新API影响的依赖类(因此不需要Foot2)。这样可以实现更好的去耦,依赖关系现在是接口而不是实现。此外,如果现有接口发生更改,则在依赖类中将出现编译错误,这对于防止代码过时很有用。

  • 如果在其他项目中重复使用该类,我们可能不需要进行所有计算

我看不出使用魔术字符串或枚举将如何帮助您...如果我正确理解,您可以将代码包含在Foot类中,或者将其分解为几个较小的类,这两种选择都适用


我喜欢带有接口的部分API的想法,这似乎是面向未来的。我会去那个。谢谢。如果它变得过于混乱(脚实现了太多的接口),则使用多个小型适配器类将更加灵活:如果存在具有不同api的多种脚形变化(例如foot,humanfoot,dogfoot,humanfootVersion2),则可能会有一个小型适配器每个都允许一个GUI小部件与它们一起使用...
Bgie 2014年

使用命令选择器的一个优点是,可以有一个实现可以接收它不理解的命令,该实现称为接口提供的静态帮助器方法。如果该命令表示使用通用方法几乎可以用所有实现来完成的事情,但是某些实现可能可以通过更好的方式来完成[请考虑例如IEnumerable<T>.Count],则这种方法可以使代码享受新代码的性能优势。使用支持它们但与旧实现保持兼容的实现时的界面功能。
超级猫

12

我会建议选择3:明确说明计算不是a的抽象的固有部分Foot,而是对其进行运算。然后,您可以将Foot计算拆分为单独的类,如下所示:

class Foot : public RecognizedObject {
public:
    // Rather low-level API to access all characteristics that might be needed by a calculation
};

class MaxPressureFrame {
public:
    MaxPressureFrame(const Foot& aFoot); // Performs the calculation based on the information in aFoot
    //API for accessing the results of the calculation
};

// Similar classes for other calculations

这样,您仍然可以对计算进行强类型输入,并且可以在不影响现有代码的情况下添加新的计算(除非您在公开的数量信息上犯了严重错误Foot)。


绝对比选项1和2更好。这距使用策略设计模式仅一步之遥。
2014年

4
这可能是适当的。这可能是矫kill过正。取决于计算的复杂程度。您要添加MaxPressureFrameStrategy和MaxPressureFrameStrategyFactory吗?并且它倾向于将脚变成贫血对象。
user949300 2014年

尽管这是一个不错的选择,但在我们的案例中,反转依赖项将无效。脚还必须充当某种调解者,因为如果另一个更改(由于用户更改了参数左右),则需要重新计算一些计算。
Bgie 2014年

@Bgie:考虑到计算之间的这种依赖性,我同意@ user116462的第一个选择是最好的。
Bart van Ingen Schenau 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.