番石榴的链接顺序

时间:2011-02-11 12:41:43

标签: java guava method-chaining

我对番石榴有点新鲜,它的风格。我肯定在挖掘它,但我不断绊倒的一件事是链式方法的顺序。我似乎有这个问题的地方最多的是使用复合Ordering s。我必须不断问自己这样的问题:

  • natural去哪了?
  • nullFirst(或最后一次)去哪儿了?
  • 哪个nullsFirst做什么? (在下面的示例中,一个用于主机,一个用于姓氏,一个用于名字?)

这是我刚刚开始研究的一个例子。它看起来很麻烦,我只是不确定我是否把它放在一起。我有一些JUnits来测试它,看起来没问题,但总有那些古怪的边界情况。

Ordering<Host> lastNameThenFirstNameOrdering = Ordering.natural().nullsFirst().onResultOf(new Function<Host, String>() {
    public String apply(Host host) {
        return host.getLastName();
    }}).compound(Ordering.natural().nullsFirst().onResultOf(new Function<Host, String>() {
    public String apply(Host host) {
        return host.getFirstName();
    }})).nullsFirst();

至于一个实际的问题:这些事情是如何被执行的,是否有明确的规则?它似乎是倒数第一,但我很难说出来。

编辑:只是想指出我试图取代的大而丑陋的代码:

    Ordering<Host> ordering2 = new Ordering<Host>() {
        public int compare(Host host1, Host host2) {
            if (host1 == null || host2 == null) {
                return host1 == host2 ? 0 : ((host1 == null) ? -1 : 1); 
            }
            if(host1.getLastName() != null || host2.getLastName() != null){
                if (host1.getLastName() == null) {
                    return -1;
                } else if (host2.getLastName() == null) {
                    return 1;
                }

                if (host1.getLastName().compareTo(host2.getLastName()) != 0) {
                    return host1.getLastName().compareTo(host2.getLastName());
                }
            }

            if (host1.getFirstName() == null) {
                return -1;
            } else if (host2.getFirstName() == null) {
                return 1;
            }

            return host1.getFirstName().compareTo(host2.getFirstName());
        }};

3 个答案:

答案 0 :(得分:24)

我认为你所做的是正确的,但非常难看。试试这个是为了便于阅读:

使用枚举

将函数移动到实现Function<Host, String>的枚举。每个枚举项都可以提供它自己的实现。

enum HostFunctions implements Function<Host, String>{
    GETFIRSTNAME{

        @Override
        public String apply(final Host host){
            return host.getFirstName();
        }
    },
    GETLASTNAME{

        @Override
        public String apply(final Host host){
            return host.getLastName();
        }
    }

}

缩进代码

现在引用那些枚举函数并正确缩进代码。这就是它的样子:

final Ordering<Host> orderingByLastAndFirstName =
    Ordering
        .natural()
        .nullsFirst()
        .onResultOf(HostFunctions.GETLASTNAME)
        .compound(
            Ordering
                .natural()
                .nullsFirst()
                .onResultOf(HostFunctions.GETFIRSTNAME))
        .nullsFirst();

我会说这让一切变得更容易理解。

IDE配置

关于正确的缩进(至少如果你使用Eclipse),请看这个问题:

  

How to indent the fluent interface pattern “correctly” with eclipse?

枚举为函数

关于枚举:这称为枚举单例模式。 Guava家伙在他们的代码库中使用它。请阅读on wikipediaEffective Java第3项。虽然这些来源都是关于单项枚举的,但这里的方法几乎相同。

答案 1 :(得分:11)

每个链接调用都会将之前的顺序“包装”为新的顺序,所以你是对的,执行顺序可以被认为是“向后”。

我编写并查看了Ordering类,我仍然经常不得不停下来,正确地交错了nullsFirst()和onResultOf()以及reverse()!

答案 2 :(得分:9)

假设您必须能够处理null主机,名字和姓氏,以下是我的首选。对我而言,似乎非null名字和姓氏应该是Host类的要求。您通常应该尽量避免允许集合包含null个对象。

Ordering<Host> lastNameFirstNameOrdering = new Ordering<Host>() {
  @Override public int compare(Host left, Host right) {
    return ComparisonChain.start()
      .compare(left.getLastName(), right.getLastName(), Ordering.natural().nullsFirst())
      .compare(left.getFirstName(), right.getFirstName(), Ordering.natural().nullsFirst())
      .result();
  }
}.nullsFirst();

或者,我会采取类似于肖恩的方法,但为了便于阅读而将其分解。

Ordering<Host> lastNameOrder = Ordering.natural().nullsFirst()
    .onResultOf(Host.LAST_NAME);
Ordering<Host> firstNameOrder = Ordering.natural().nullsFirst()
    .onResultOf(Host.FIRST_NAME);
Ordering<Host> orderingByLastAndFirstName =
     lastNameOrder.compound(firstNameOrder).nullsFirst();

请注意,您还可以将这些单独的排序设置为类的静态最终字段,以便在排序时Host.LAST_NAME_ORDER轻松地在任何位置使用它们。