9

我有一个带有 List 属性的 Java AutoValue 类。我想让构建器附加到列表中,而不必传递整个构造的列表。

例子:

import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Deck {
    public abstract List<Card> cards();
    public static Builder builder() {
        return new AutoValue_Card.Builder()
            .cards(new ArrayList<Card>());
    }
    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder cards(List<Card> cards);
        /**
         * Append card to cards in the constructed Deck.
         */
        public Builder addCard(Card card) {
            // Is it possible to write this function?
        }
    }
}

编写 addCard 函数的最佳解决方案是什么?AutoValue 是否已经以某种方式支持这一点?构建类中的中间卡属性对 Builder 不可见,因此我无法直接访问它。我可以尝试通过将自己的卡片副本保留在 Builder 中来直接绕过 Builder,这是唯一的选择吗?

4

2 回答 2

7

当您使用 Guava 的不可变集合时, AutoValue 有一些特殊功能会发挥作用,因为这些集合都有自己关联的构建器类型。(当然,您当然希望值类的属性是不可变的!)

一个特性是您可以定义一个抽象cardsBuilder()方法,该方法将启动适当集合类型的新构建器并将其返回给调用者。这是超级灵活的,但令人遗憾的是它“打破了链条”。来电者现在在 an 上拨打电话,ImmutableList.Builder无法返回Deck.Builderto call build

但是你可以通过添加你自己的addCard方法来解决这个问题,就像你在上面展示的那样,只需实现它来调用cardsBuilder().add(card)然后返回this而不是构建器。问题解决了!

我相信所有这些都应该在 1.1 中起作用,但如果您遇到问题,请告诉我们!

PS 我很抱歉——我们有很多关于 AutoValue 用户指南的新材料,包括这个主题,由于一些技术困难,这些材料一直被推迟到公共网站上。

于 2015-12-11T23:29:43.513 回答
4

如果有人发现它有用 - 这是我假设凯文建议的实际代码。当我第一次偶然发现他的回复时,这并不明显,所以你去吧:

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;

@AutoValue
public abstract class Hand {
  public static Builder builder() {
    return new AutoValue_Hand.Builder();
  }

  public abstract Builder toBuilder();

  public abstract String name();

  public abstract ImmutableList<String> cards();

  @AutoValue.Builder
  public static abstract class Builder {

    public abstract Builder name(String name);

    protected abstract ImmutableList.Builder<String> cardsBuilder();

    public Builder addCard(String card) {
      cardsBuilder().add(card);
      return this;
    }

    public abstract Hand build();
  }
}

用法:

Hand fullHouseHand = Hand.builder()
    .name("Full House")
    .addCard("King")
    .addCard("King")
    .addCard("King")
    .addCard("10")
    .addCard("10")
    .build();
System.out.print(fullHouseHand);

输出:

Hand{name=Full House, cards=[King, King, King, 10, 10]}
于 2016-06-14T21:54:46.377 回答