[[[Edit: Nhập mã để chứng minh khái niệm hoàn toàn bất biến]]]
Đó là lý do tại sao các nhà xây dựng rất tốt đẹp cho immutables - chúng cho phép khả năng thay đổi trong khi xây dựng để mọi thứ được thiết lập trước khi bạn "đóng băng" nó. Trong trường hợp này, tôi đoán bạn cần một người xây dựng Friend hỗ trợ tạo chu kỳ.
final FriendBuilder john = new FriendBuilder().setName("john");
final FriendBuilder mary = new FriendBuilder().setName("mary");
final FriendBuilder susan = new FriendBuilder().setName("susan");
john
.likes(mary)
.likes(susan);
mary
.likes(susan)
.likes(john);
susan
.likes(john);
// okay lets build the immutable Friends
Map<Friend> friends = FriendsBuilder.createCircleOfFriends(john, mary, susan);
Friend immutableJohn = friends.get("john");
Chỉnh sửa: Thêm dụ bất biến dưới đây để chứng minh phương pháp:
Có một số cuộc thảo luận trong các ý kiến về việc liệu một phiên bản bất biến là có thể.
Các trường là cuối cùng và không thay đổi. Một bộ có thể sửa đổi được sử dụng trong hàm tạo, nhưng nó chỉ là tham chiếu không thể sửa đổi được giữ lại sau khi xây dựng.
Tôi có một phiên bản khác sử dụng Guava ImmutableSet cho bộ thực sự không thay đổi được chứ không phải là trình bao bọc không thể sửa đổi của JDK. Nó hoạt động tương tự, nhưng sử dụng công cụ xây dựng bộ tốt đẹp của Guava.
Code:
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
/**
* Note: potentially cycle graph - be careful of deep equals/hashCode/toString/etc.
* Immutable
*/
public class Friend {
public static class Builder {
private final String name;
private final Set<Builder> friends =
new HashSet<Builder>();
Builder(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public Set<Builder> getFriends() {
return friends;
}
void likes(final Builder... newFriends) {
for (final Builder newFriend : newFriends)
friends.add(newFriend);
}
public Map<String, Friend> createCircleOfFriends() {
final IdentityHashMap<Builder, Friend> existing =
new IdentityHashMap<Builder, Friend>();
// Creating one friend creates the graph
new Friend(this, existing);
// after the call existingNodes contains all the nodes in the graph
// Create map of the all nodes
final Map<String, Friend> map =
new HashMap<String, Friend>(existing.size(), 1f);
for (final Friend current : existing.values()) {
map.put(current.getName(), current);
}
return map;
}
}
final String name;
final Set<Friend> friends;
private Friend(
final Builder builder,
final Map<Builder, Friend> existingNodes) {
this.name = builder.getName();
existingNodes.put(builder, this);
final IdentityHashMap<Friend, Friend> friends =
new IdentityHashMap<Friend, Friend>();
for (final Builder current : builder.getFriends()) {
Friend immutableCurrent = existingNodes.get(current);
if (immutableCurrent == null) {
immutableCurrent =
new Friend(current, existingNodes);
}
friends.put(immutableCurrent, immutableCurrent);
}
this.friends = Collections.unmodifiableSet(friends.keySet());
}
public String getName() {
return name;
}
public Set<Friend> getFriends() {
return friends;
}
/** Create string - prints links, but does not traverse them */
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("Friend ").append(System.identityHashCode(this)).append(" {\n");
sb.append(" name = ").append(getName()).append("\n");
sb.append(" links = {").append("\n");
for (final Friend friend : getFriends()) {
sb
.append(" ")
.append(friend.getName())
.append(" (")
.append(System.identityHashCode(friend))
.append(")\n");
}
sb.append(" }\n");
sb.append("}");
return sb.toString();
}
public static void main(final String[] args) {
final Friend.Builder john = new Friend.Builder("john");
final Friend.Builder mary = new Friend.Builder("mary");
final Friend.Builder susan = new Friend.Builder("susan");
john
.likes(mary, susan);
mary
.likes(susan, john);
susan
.likes(john);
// okay lets build the immutable Friends
final Map<String, Friend> friends = john.createCircleOfFriends();
for(final Friend friend : friends.values()) {
System.out.println(friend);
}
final Friend immutableJohn = friends.get("john");
}
}
Output:
Node 11423854 {
value = john
links = {
susan (19537476)
mary (2704014)
}
}
Node 2704014 {
value = mary
links = {
susan (19537476)
john (11423854)
}
}
Node 19537476 {
value = susan
links = {
john (11423854)
}
}
Nguồn
2011-01-29 01:45:15
Bạn có biết trước tất cả các mối quan hệ hai chiều bạn cần hoặc bạn có thêm từng mối quan hệ một lúc không? Trong trường hợp sau, thực sự không có cách nào để có được sự đảm bảo bất biến, vì bạn thực sự đang thay đổi các đối tượng. – templatetypedef
Trong trường hợp này - không, im cố gắng giữ đơn giản này. –