有没有什么好的方法可以使不可变对象链循环?

Any nice way to make a chain of immutable objects loop around?

此问题是 this question 的延伸。

我有一个class类似于下面的。

 class HighlightableStructure {
      private final HighlightableStructure NEXT;  

      HighlightableStructure(HighlightableStructure next) {
           NEXT = next;
      }    
 }

其中 HighlightableStructure 指向下一个要突出显示的结构。

有时,这些 HighlightableStructure 循环并引用前一个 HighlightableStructure,但不是链中的第一个。类似于 h_1 -> h_2 ->h_3 -> ... -> h_n -> h_2,其中 h_i 是一个实例HighlightableStructure 个。

无论如何我可以构建这样的东西而不需要反思或失去不变性吗?

一种可能的解决方案:

class HSequenceBuilder {
    private long id = 0;
    private final Map<Integer, H> map = new HashMap<Integer, H>();

    static H create(int next) {
        H h = new H(id, next, Collections.unmodifiableMap(map));
        map.put(id, h);
        id++;
        return h;
    }

    static H create() {
        create(id + 1);
    }

}

class H {
    private final id;
    private final Map<Integer, H> map;
    private final int next;

    H(int id, int next, Map<Integer, H> map) {
        this.id = id;
        this.next = next;
        this.map = map;
    }

    int getId() { return id; }
}
HSequenceBuilder builer = new HSequenceBuilder();
H h1 = builder.create(); // 1.
H h2 = builder.create(); // 2.
H h3 = builder.create(h2.getId()); // 3.

你有一个链表,它要求它的节点是可变的。如果您发布节点的安全副本,您可以拥有可变对象,但仍然可以获得与不变性非常相似的好处。

将您的节点隐藏在一个包含对象中,当您的 API 必须 return 一个节点时,return 它的一个副本,甚至是整个结构的副本(根据需要) .

answer of the linked question 很容易扩展到任意数量的对象,如果你有办法在构建时指定所需的节点,例如

final class CircularLinkedList<T> {
    final CircularLinkedList<T> next;
    final T value;

    public CircularLinkedList(T firstValue, List<T> other) {
        value = firstValue;
        next = other.isEmpty()? this: new CircularLinkedList<>(this, 0, other);

    }
    private CircularLinkedList(CircularLinkedList<T> head, int pos, List<T> values) {
        value = values.get(pos);
        next = ++pos == values.size()? head: new CircularLinkedList<>(head, pos, values);
    }

    @Override
    public String toString() {
        StringJoiner sj = new StringJoiner(", ").add(value.toString());
        for(CircularLinkedList<T> node = next; node != this; node = node.next)
            sj.add(node.value.toString());
        return sj.toString();
    }
}

你可以使用它

CircularLinkedList<String> cll
    = new CircularLinkedList<>("first", Arrays.asList("second", "third", "fourth"));
System.out.println(cll);

// demonstrate the wrap-around:
for(int i = 0; i < 10; i++, cll = cll.next) {
    System.out.print(cll.value+" .. ");
}
System.out.println(cll.value);