方法名称与流畅接口

7

我有一个Java的Permissions类,其中的方法使用流畅的风格,像这样:

somePermissions.setRead(true).setWrite(false).setExecute(true)

问题是,我是否应该将这些方法命名为set{Property}还是仅使用{property}。后者看起来像这样:

somePermissions.read(true).write(false).execute(true)

如果我分开看这些方法,我会期望read读取一些东西,但另一方面它更接近于在Scala中具有类似命名参数的意图:

Permission(read=true, write=false, execute=true)

2
愚蠢的问题,但为什么不使用命名和默认参数呢?至少对于你给出的示例来说,这是最简洁和最易读的。 - Miles Sabin
2
我应该说我使用的是Java,它不支持命名参数和默认参数。 - deamon
4个回答

8

set{Property}比只使用{property}更能传达意图。但是,由于您的示例是简单的布尔属性,一个更好的流畅接口可能是:

somePermissions.AllowRead().DenyWrite().AllowExecute();

没问题,但你应该考虑处理这种无意义的链接情况:AllowRead().DenyRead() - oxbow_lakes
@oxbow_lakes 为什么?如果你先允许然后再禁止,抽烟对你来说可以吗?在我看来这是很清楚的(尽管你可能想防止这种情况发生,因为它们可能是错误导致的)。 - maaartinus

6

这是流畅接口中的一个经典问题。虽然我同意@Bozho的看法,setRead()更加自解释,但在流畅接口中的目标是使整个“句子”可读,而不是使单个方法调用可读。

因此,我会更进一步。如何:

somePermissions.readable().nonWritable().executable()

请参考Martin Fowler关于此主题的文章。他说:“构建这样的流畅API会导致一些不寻常的API习惯。”


5
set{Property}是一定要使用的。它告诉我们这个方法在做什么。想象一下,如果你的属性名叫做visibleencoding或者algorithm,那么不使用set就没有任何意义了。
你可以使用更具描述性的动作名称,与属性名不同。例如: visible -> show(..)
encoding -> encode(..)
read > makeReadable(..)
name -> giveName(..)("name"是一个动词,但含义不明确)

1

set 显然会影响清晰度。它们并不像 bean 那样的方法,所以我建议放弃。

我还建议将构建器与产品分开。在产品中更喜欢不可变性。

如果你有标志,我认为最好使用布尔值而不是一对方法。Java 库在从 1.0 到 1.1 进行了这个更改。然而,我仍然不喜欢布尔值。在 truefalse 中没有太多高级含义。枚举类型更好。更好的是,如果你谈论的是可以被视为集合的东西(如示例中),那么使用 Set(可能实现为 EnumSet)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接