Simulating inheritance+mutable state with immutable objects
我在用不变的对象建模我们的领域时遇到了一个问题。
可变设计
一个基本特征wObject(World Object)和用于执行特定操作的大量特征,如ownedobj(HP/Owner/TakeDamage)、moved(movementLeft/moveto)、fighter(attacked/attack)。
在层次结构的末尾,有一个可变类,它混合了适当的特性:
如果用户想要执行操作(比如移动船舶),则需要执行以下操作:
1 2 3 4 |
不变的设计
如果moveto必须返回一个新对象,它返回什么类型?
我曾经尝试过使用
我还尝试了在traits中使用类型边界方法抽象类型self,但是在以下场景中,这开始变得复杂起来:
把这个嵌套一点,你就会得到
1 2 3 | def attackReachable( data: WObject.WorldObjUpdate[Self] ): WObject.WorldObjUpdate[data.value._2.Self] |
太可怕了。
我在考虑放弃继承并使用composition+typeclasss,但我不太确定该怎么做。
例如:
1 2 3 4 5 6 7 8 9 10 | case class WObject(position: Vect2, id: UUID=UUID.randomUUID()) case class OwnedObj(owner: Owner) case class Movable(movementLeft: Int) case class Fighter(attacked: Boolean) case class Corvette(obj: WObject, owned: OwnedObj, movable: Movable, fighter: Fighter) // Something that has both WObject and Movable trait MovableOps[A <: ???] { def moveTo(obj: A, target: Vect2): A } |
然后在typeclasses中定义操作,这些操作将在CorvetteCompanion对象中实现。
但是我不知道如何指定限制条件。
关于如何从客户端实现移动操作的更多信息?
1 2 3 4 |
感谢您的帮助:)
相关:不可变类层次结构中的多态更新
你可以用一个存在主义的例子来写你的"同一个"案例:
如果我正确理解了您的
如果你想走合成路线,我能想到的最好的方法是使用无形状镜片(我不能与单镜头相比,因为我没有使用过它们):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | trait Move[A] { val lens: Lens[A, (WObject, Movable)] } /** This could be implicitly derived with Generic if you really want to - or you could use Records. */ implicit def moveCorvette = new Move[Corvette] { val lens = lens[Corvette].obj ~ lens[Corvette].movable } def moveTo[A: Move](obj: A, target: Vect2) = { val l = Lens[A, (Wobject, Movable)] val remainingMoves = l.get(obj)._2.movementLeft - 1 l.set(obj)((target, remainingMoves)) } |
要将此应用于列表,您可以将列表保留为HLIST,以便了解所有元素的类型(例如,您的列表是