Полиморфные обновления в неизменной иерархии классов

Я хотел бы иметь возможность собирать доменные объекты из признаков в соответствии с различными свойствами, которые могут иметь конкретные классы. Когда мои объекты изменчивы, это довольно просто. Например:

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 }

В частности, я могу полиморфно читать или обновлять любые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

Кроме того, я могу легко изменить конкретные классы, используяcopy если я знаю точный тип. Сложная часть заключается в обновлении произвольногоHasHitPoints, например. Если у меня есть много конкретных классов и много разных свойств, которые я хотел бы добавить, какова лучшая схема, чтобы избежать взрыва шаблонного кода?

Ответы на вопрос(3)

Ваш ответ на вопрос