不可变类层次结构中的多态更新

Mat*_*t R 19 inheritance scala immutability

我希望能够根据具体类可能具有的各种属性从特征组装域对象.当我的对象是可变的时,这非常简单.例如:

trait HasHitPoints { var hitPoints: Int = 100 }
trait HasBearing { var bearing: Double = 0 }

class Ship extends HasHitPoints with HasBearing
class Base extends HasHitPoints

val entities = new Ship :: new Base :: Nil
entities.collect { case h: HasHitPoints => h.hitPoints += 10 }
Run Code Online (Sandbox Code Playgroud)

特别是,我可以在HasHitPoints不知道具体类型的情况下以多态方式读取或更新任何实例.

使用不可变对象实现此操作的最佳方法是什么?如果我很高兴只阅读属性,那么我可以做类似的事情:

trait HasHitPoints { val hitPoints: Int }
trait HasBearing { val bearing: Double }

case class Ship(hitPoints: Int, bearing: Double) extends HasHitPoints with HasBearing
case class Base(hitPoints: Int) extends HasHitPoints

val things = Ship(50, 0) :: Base(100) :: Nil

val totalHitPoints = things.collect { case h: HasHitPoints => h.hitPoints }.sum
Run Code Online (Sandbox Code Playgroud)

此外,copy如果我知道精确类型,我可以轻松修改具体类.例如,困难的部分是更新任意HasHitPoints.如果我有很多具体的类,以及许多不同的属性,我可能想要混合使用,避免样板代码爆炸的最佳方案是什么?

Tom*_*bel 1

您可能会幸运地向您的特征添加一个例如抽象 def withHitPoints(points: Int) 方法,该方法返回具有不同属性值的容器对象的副本。这将使用量减少为:

val damagedActors = actors map { actor => actor.withHitPoints( actor.hitPoints - 10 ) }
Run Code Online (Sandbox Code Playgroud)

但否则将需要每个具体类的每个属性一个额外的方法,所以我不确定它是否真正解决了您的问题。对于像 Scala 这样的静态语言来说,这感觉不太合适(我也不太可能为这个特定用例的不变性而烦恼);这里的不可变解决方案可能是动态语言的更好候选者。

  • 可能,虽然我想知道 Sapir-Whorf 的事情在多大程度上是这样的:一种语言不能很好处理的场景变成了不经常出现的场景...... (2认同)