guava如何设计一个包含java的不可变值类。什么是弦?
客观的
创建一个类,用作String对象的不可变列表
接近
我决定利用{a2}的{a3}集合,而不是用{a5}包装一个简单的{a4},因为我知道这样可以避免对后台{a4}进行不必要的并发检查,而后台{a4}不知道被包装(来源:ImmutableCollectionsExplained)
要求
- 类可以是跨线程使用的“值持有者”
- 创建后不允许任何代码更改内部值
很高兴拥有
- 类应该实现Iterable<E>以便按照创建顺序对值进行迭代
- 对于给定的String集,应该只有一个类
尝试
这里有一些尝试,尽管可能有更多的组合。原谅这个幽默的表演
尝试#1(包括使用示例)
import java.util.List;
import com.google.common.collect.ImmutableList;
class BritnetSpearsSpellings implements Iterable<String> {
public static BritnetSpearsSpellings of(String... spellings) {
BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings();
britneySpears.spellings = ImmutableList.copyOf(spellings);
return britneySpears;
}
private List<String> spellings;
private BritnetSpearsSpellings() {
}
public List<String> getSpellings() {
return spellings;
}
}
@Override
public Iterator<String> iterator() {
return spellings.iterator();
}
public class Usage {
public static void main(String[] args) {
for (String sepllin : BritnetSpearsSpellings.of("Brittany Spears", "Brittney Spears", "Britany Spears"))
System.out.printf("You spel Britni like so: %s%n", sepllin);
}
}
}
尝试#2
class BritnetSpearsSpellings implements Iterable<String> {
public static BritnetSpearsSpellings of(String... spellings) {
BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings();
britneySpears.spellings = ImmutableList.copyOf(spellings);
return britneySpears;
}
private ImmutableList<String> spellings;
private BritnetSpearsSpellings() {
}
public ImmutableList<String> getSpellings() {
return spellings;
}
@Override
public Iterator<String> iterator() {
return spellings.iterator();
}
}
尝试#3
class BritnetSpearsSpellings implements Iterable<String> {
public static BritnetSpearsSpellings of(String... spellings) {
BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings(ImmutableList.copyOf(spellings));
return britneySpears;
}
private final ImmutableList<String> spellings;
private BritnetSpearsSpellings(ImmutableList<String> spellings) {
this.spellings = spellings;
}
public ImmutableList<String> getSpellings() {
return spellings;
}
@Override
public Iterator<String> iterator() {
return spellings.iterator();
}
}
差异摘要
1将List<E>保存在公共接口中,记录JavaDoc中的不变性
2以Google Guava的ImmutableList<E>存储和公开所有内容
3以创建专门构造函数为代价,将内部引用保持为最终引用,在没有其他初始化选项的情况下,可能会使静态工厂方法初始化看起来很愚蠢(在实际类中实际存在)
问题:
请帮助我从这些实现中选择一个,并说明选择背后的原因
我认为方法#2的主要缺点是客户需要对专业的Google Guava类型有认知/可见性,而他们可能不应该
# 1 楼答案
从你的问题陈述(“一组给定的字符串应该只有一个类”),听起来你真正想要的是一个
Interner<ImmutableSet<String>>
Interners.newStrongInterner()
构造一个),用于确保只有一个对象的实例包含任何给定数据李>或者,您可能希望查看
Cache<ImmutableSet<String>>
(有关详细信息,请参见Caches Explained)# 2 楼答案
显然,在我看来#3是最好的选择
final
强制并记录类(该字段)的不可变性,而不仅仅是List
本身是不可变的无论是在getter中用一些javadoc公开
List
还是实际的ImmutableList
都是另一回事。我看到过一些观点,返回ImmutableList
清楚地记录了意图,但仍然是将自己绑定到一个实现上,而不是一个接口,用于一些低级别的东西,并且将来可能需要更改(即使不变性“通常”是好的)。因此,对于您的应用程序来说,它更像是一种全球性的设计选择,而不仅仅是一个用例。如果你使用ImmutableList
,我不认为这对客户端来说是一个真正的问题,它的名字是明确的,通过你的IDE可以很容易地看到它是List
的实现,如果他们想要更多信息,他们可以访问javadoc。谁知道呢,他们可能会喜欢它,并开始使用它,以及番石榴提供的所有其他好吃的东西:-)# 3 楼答案
我会在
Attempt #1
上使用Attempt #2
,因为它记录了您总是返回ImmutableList实例的情况。一般来说,选择尽可能具体的返回类型和尽可能一般的参数类型是很有用的。但对于这两种情况,我们更喜欢接口而不是具体的类嗯,
ImmutableList
是一个抽象类,而不是一个接口。但由于其本质,它的行为非常像一个接口当类成员引用
spellings
在对象的生命周期内无法更改,和/或希望整个类本身不可变时,Attempt #3
是有意义的。否则,当spellings
可以在对象生存期内分配给另一个ImmutableList时,它就没有意义了考虑到你例子中的用例,我倾向于说#3是最好的选择