在之前的SO post中,我询问了一种使用容器类包装不可变集合线程安全的惯用方法。我收到的所有涉及使用各种风格的读/写锁或同步的答案,这不是我想要的。
让我问一个不同的问题。如何使包含不可变容器的以下类不可变?方法add
/ remove
需要返回一个适当更改的新MyContainer
类实例,但我不太明白该怎么做...
class MyContainer[A] {
// method that returns a new MyContainer that includes the additional thing...
def add(thing: A): MyContainer[A] = {
???
}
def filter(p: A => Boolean): Option[Iterable[A]] = {
val filteredThings = backingStore.values.filter(p)
if (filteredThings.isEmpty) None else Some(filteredThings)
}
// method that returns a new MyContainer that does not include the thing with given uuid
def remove(uuid: UUID): MyContainer[A] = {
???
}
@ volatile private[this] var backingStore = immutable.HashMap.empty[UUID, A]
}
思想?
编辑:在回应评论时,一种可能的解决方案类似于以下内容......
class MyContainer[A](val backingStore: immutable.HashMap[UUID, A]) {
def add(thing: A): MyContainer[A] = {
new MyContainer(backingStore + (thing.uuid -> thing))
}
def filter(p: A => Boolean): Option[Iterable[A]] = {
val filteredThings = backingStore.values.filter(p)
if (filteredThings.isEmpty) None else Some(filteredThings)
}
def remove(uuid: UUID): MyContainer[A] = {
new MyContainer(backingStore - uuid)
}
}
... backingStore
不再是私有的(但可以将private
放在构造函数中)。更多想法?
答案 0 :(得分:1)
您需要一种方法来构造一个已包含一些元素的新MyContainer
,并且最好保持相同的UUID。这意味着你将基本上需要一个初始化backingStore
的构造函数。但是,如果您不想以任何方式公开它,可以将构造函数设置为private,并提供一个重载的构造函数,该构造函数只允许外部代码创建一个空集合(比方说)。 backingStore
可以简单地移动到私有构造函数中。
class MyContainer[A] private (backingStore: HashMap[UUID, A]) {
def this() = this(HashMap.empty[UUID, A])
def add(thing: A): MyContainer[A] = {
val uuid: UUID = UUID.randomUUID() // or however the UUID is generated
new MyContainer(backingStore + ((uuid, thing)))
}
def remove(uuid: UUID): MyContainer[A] =
new MyContainer(backingStore - uuid)
}
scala> val container = new MyContainer[String]()
scala> container.add("a").add("b").add("c")
res2: MyContainer[String] = MyContainer@4a183d02
但是,您希望在API中公开这一点。我不确定你对filter
的要求是什么,所以我从我的例子中删除了它。