15

“API 设计就像性:犯一个错误并在你的余生中支持它” 推特上的乔什·布洛赫

Java 库中有很多设计错误。Stack extends Vector讨论),我们不能在不造成损坏的情况下解决这个问题。我们可以尝试弃用Integer.getInteger讨论),但它可能会永远存在。

尽管如此,可以在不造成损坏的情况下进行某些类型的改造。

Effective Java 第 2 版,第 18 项:优先使用接口而不是抽象类:现有类可以很容易地改造以实现新接口”。

示例:String implements CharSequenceVector implements List等。

Effective Java 第 2 版,第 42 条:明智地使用可变参数:您可以改进现有的方法,该方法将数组作为其最终参数以采用可变参数,而不会对现有客户端产生影响。

一个(不)著名的例子是Arrays.asList,它引起了混乱(讨论),但没有破坏。

这个问题是关于一种不同类型的改造:

你能在void不破坏现有代码的情况下改造一种方法来返回一些东西吗?

我最初的预感是肯定的,因为:

  • 返回类型不影响编译时选择的方法
  • 即使您使用反射,Class.getMethod也无法区分返回类型

但是,我想听听其他在 Java/API 设计方面更有经验的人进行更彻底的分析。


附录:动机

正如标题中所建议的,一个动机是促进流畅的界面风格编程。

考虑这个简单的代码片段,它打印一个打乱的名字列表:

    List<String> names = Arrays.asList("Eenie", "Meenie", "Miny", "Moe");
    Collections.shuffle(names);
    System.out.println(names);
    // prints e.g. [Miny, Moe, Meenie, Eenie]

已经Collections.shuffle(List)声明返回输入列表,我们可以这样写:

    System.out.println(
        Collections.shuffle(Arrays.asList("Eenie", "Meenie", "Miny", "Moe"))
    );

如果它们要返回输入列表而不是,等,那么使用其他方法Collections会更愉快。事实上,拥有和返回尤其不幸,因为它剥夺了我们编写表达代码的能力,void例如像这样:reverse(List)sort(List)Collections.sortArrays.sortvoid

// DOES NOT COMPILE!!!
//     unless Arrays.sort is retrofitted to return the input array

static boolean isAnagram(String s1, String s2) {
    return Arrays.equals(
        Arrays.sort(s1.toCharArray()),
        Arrays.sort(s2.toCharArray())
    );
}

当然,这种void阻碍流畅性的返回类型不仅限于这些实用方法。这些java.util.BitSet方法也可以编写为返回this(alaStringBufferStringBuilder) 以促进流畅性。

// we can write this:
    StringBuilder sb = new StringBuilder();
    sb.append("this");
    sb.append("that");
    sb.insert(4, " & ");
    System.out.println(sb); // this & that

// but we also have the option to write this:
    System.out.println(
        new StringBuilder()
            .append("this")
            .append("that")
            .insert(4, " & ")
    ); // this & that

// we can write this:
    BitSet bs1 = new BitSet();
    bs1.set(1);
    bs1.set(3);
    BitSet bs2 = new BitSet();
    bs2.flip(5, 8);
    bs1.or(bs2);
    System.out.println(bs1); // {1, 3, 5, 6, 7}

// but we can't write like this!
//  System.out.println(
//      new BitSet().set(1).set(3).or(
//          new BitSet().flip(5, 8)
//      )
//  );

不幸的是,与StringBuilder/不同StringBuffer所有BitSetmutators 都返回void

相关话题

4

3 回答 3

14
于 2010-08-28T07:54:13.613 回答
1

如果你不能改造,你仍然可以将你的类包装成一个使用相同方法但返回正确的新类(MyClassFluent)。或者您可以添加新方法但名称不同,而不是Arrays.sort()我们可以拥有Arrays.getSorted().

我认为解决的办法不是强迫事情,而是处理它们。

编辑:我知道我没有回答“改造无效方法”的问题,但你的答案已经很清楚了。

于 2010-08-28T08:45:34.307 回答
1

如果您只需要处理源兼容性,那就继续吧。从 void 更改为返回类型不会中断。

但是要解决您真正想要做的事情:我认为流畅界面的问题是行往往会变得相当长并且 - 在格式化之后 - 有点不可读。对于建设者来说,它工作得很好,但我可能不会将它用于其他任何事情。

这是为了玩它,还是因为你发现它真的很棒?

于 2010-08-28T09:41:49.707 回答