有没有什么好的方法可以使不可变对象链循环?
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);
此问题是 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);