如何在Scala中实现不可变类的封装,避免私有构造参数对外暴露?
Scala 实现方案
首先给出符合你需求的不可变Profile实现:
import scala.collection.immutable.List // 主构造函数私有,外部无法直接调用 case class Profile private ( private val _inSyncBikeIds: List[String], val profileName: String ) { def synchronize(bikeId: String): Profile = // 内部调用自动生成的copy方法修改私有字段 this.copy(_inSyncBikeIds = _inSyncBikeIds :+ bikeId) def isInSync(bikeId: String): Boolean = _inSyncBikeIds.contains(bikeId) def reset(): Profile = this.copy(_inSyncBikeIds = Nil) // 对外暴露的copy方法,仅允许修改公共字段 def copy(profileName: String = this.profileName): Profile = Profile(profileName) } object Profile { // 对外唯一公开构造入口,强制_inSyncBikeIds初始值为空列表 def apply(profileName: String): Profile = Profile(Nil, profileName) }
问题解答
如何在Scala中解决该问题?
核心方案是私有主构造函数 + 伴生对象暴露公开构造入口 + 自定义对外copy方法:
将所有字段放入case class的主构造参数列表,把主构造函数设为private,外部无法直接调用主构造函数也无法直接使用自动生成的全参数copy方法。伴生对象的apply方法仅接收公共的profileName参数,强制_inSyncBikeIds初始值为空列表,满足初始化约束。同时在类内部自定义对外暴露的copy方法,仅开放公共字段的修改权限,隐藏私有字段的修改能力。我在类内部使用
copy方法时,能否通过copy方法修改私有字段?
可以。case class自动生成的copy方法访问权限和主构造函数完全一致,主构造函数为类私有情况下,自动生成的copy方法也仅对类内部和伴生对象可见,类内部调用时可以正常修改所有构造参数中的字段,包括私有val字段。Scala的
copy方法是否会复制私有字段,哪怕这些字段不是构造参数的一部分?
不会。Scala case class自动生成的copy方法只会处理主构造参数列表中的字段,不属于主构造参数的类成员不会被copy方法识别,也不会被自动复制。如果存在非构造参数的私有字段,需要手动实现copy逻辑处理这些字段的值。
内容的提问来源于stack exchange,提问作者Niklas Raab
相关产品推荐
相关产品推荐

