【问题标题】:How should I design a method that allows for optional operations?我应该如何设计一种允许可选操作的方法?
【发布时间】:2010-06-28 00:44:34
【问题描述】:

例如,假设我是这样的:

class Gundam00 extends Gundam implements MobileSuit {
    ...

    public void fight(final List<MobileSuit> mobiruSuitso, final List<Gundam> theOtherDudes, final List<Person> casualities) {
        ....
    }
}

假设OtherDudes 和casualities 参数是可选的。我怎样才能使这种方法尽可能干净?我想过让布尔值指示它们是否为空,然后根据需要检查它们。

我也可以为每种参数组合使用不同版本的方法,但我认为会有很多代码重复。

有什么建议吗?

【问题讨论】:

标签: language-agnostic design-patterns


【解决方案1】:

我发现过去 2-3 个参数,记住函数的所有参数的能力会受到影响。以及随之而来的可理解性。

传递命名参数会有所帮助。具有方便的类似散列的文字语法的语言使这变得非常容易。以 JavaScript 为例:

g = new Gundam00();
g.fight({opponent: enemy, casualties: 'numerous'});

您还可以利用可变长度参数功能来处理此问题(将奇数参数视为名称,将偶数参数视为实际参数)。

g.fight('opponent',enemy,'casualties', 'numerous');

有些语言实际上直接支持命名参数(参见:http://en.wikipedia.org/wiki/Named_parameter#Use_in_programming_languages)。

最后,您可能需要考虑为此添加其他方法,使用所谓的 Fluent 接口 (http://en.wikipedia.org/wiki/Fluent_interface)。基本上,你有返回对象本身的方法调用,所以你可以将调用链接在一起:

g.opponent(enemy).casualties('numerous').fight();

如果您使用的是明显/静态类型的以类为中心的语言,这可能是最简单的选择。

更新

回应 Setsuna 的评论...在最后一个示例中,如果您有足够的能力,您可以制作像 opponentcasualties 这样的简单设置器,它们不会影响任何其他内部状态或计算比设置为其命名的参数的方式。他们只是简单地设置内部属性,然后所有的实际工作都发生在像fight 这样的操作方法中。

如果你不能这样做(或者如果你不喜欢编写操作是亚原子的方法),你可以在这个想法和类似哈希的文字想法之间找到一个中间点,然后创建您自己的集合类,专门用于调用命名参数:

n = new NArgs();  
g.fight(n.arg('opponent',enemy).arg('casualties','numerous').arg('motion','slow'));

有点笨拙,但它分离了命名参数问题并让您的方法更加原子化,并且 NArgs 可能是您可以很容易实现的东西,只需将一些方法包装在一种类型的 Collection(HashTable?)或以您的语言提供的其他语言。

【讨论】:

  • 最后一种方法是我最初想到的——装饰器——但操作必须同时执行。所以我想不出添加它们的方法。我确定有,我只是不习惯这种模式。
  • 您可以只创建 opponentcasualties 基本设置器并将真正的工作留在 fight... 但如果这不适合您的情况,您可以创建一个命名参数使用该想法的类。我刚刚更新了我的答案以反映这一点。
【解决方案2】:

添加方法。重载方法通常是一种反模式,也是其他人的重构机会。

http://www.codinghorror.com/blog/2007/03/curlys-law-do-one-thing.html

【讨论】:

    【解决方案3】:

    我想过让布尔值指示它们是否为空,然后在内部检查它们并做出相应的反应。

    或者......你可以检查它们是否为空。

    if(theOtherDudes == null)
        ...
    

    【讨论】:

    • 我的意思是做final boolean anyAllies = theOtherDudes == null 并在我必须使用该参数时检查它。以便。我编辑了帖子以使其更清晰。
    • 在没有“other dudes”的情况下,你应该传入一个空集合而不是传递null。
    • 既然你提到它,传递一个空集合听起来更好。
    【解决方案4】:

    如果您的类中只有一个“主要方法”,那么您可以将可选参数实现为 getter/setter 函数。示例:

    public void setOtherDudes(final List<Gundam> theOtherDudes) {} // for input arguments
    public List<Person> getCasualities() {} // for output arguments
    

    然后,在您的文档中,提到如果调用者有任何可选的输入参数,则必须在调用 fight() 之前将其传入,并且当调用 fight() 时,可选的输出值将可用。

    如果有几十个可选参数,这是值得的。否则,我建议重载方法作为最简单的方法。

    【讨论】:

      猜你喜欢
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-07
      • 1970-01-01
      • 2016-12-12
      • 1970-01-01
      相关资源
      最近更新 更多