【发布时间】:2020-10-22 08:09:14
【问题描述】:
我很难决定何时使用 defrecord 是正确的选择,更广泛地说,如果我在记录中使用的协议是语义 clojure 和功能性的。
在我当前的项目中,我正在构建一个游戏,其中包含不同类型的敌人,它们都有相同的动作集,而这些动作的实现方式可能不同。
来自 OOP 背景,我很想这样做:
(defprotocol Enemy
"Defines base function of an Enemy"
(attack [this] "attack function"))
(extend-protocol Enemy
Orc
(attack [_] "Handles an orc attack")
Troll
(attack [_] "Handles a Troll attack"))
(defrecord Orc [health attackPower defense])
(defrecord Troll [health attackPower defense])
(def enemy (Orc. 1 20 3))
(def enemy2 (Troll. 1 20 3))
(println (attack enemy))
; handles an orc attack
(println (attack enemy2))
;handles a troll attack
从表面上看,这似乎是有道理的。我希望每个敌人总是有一种攻击方法,但实际实施应该能够因特定敌人而异。使用extend-protocol,我可以高效地调度因敌人而异的方法,并且可以轻松添加新的敌人类型以及更改这些类型的功能。
我遇到的问题是为什么我应该在通用地图上使用记录?以上对我来说有点 OOP 的感觉,并且似乎我正在反对一种更实用的风格。所以,我的问题分为两个:
- 我上面的记录和协议实现是一个合理的用例吗?
- 更笼统地说,什么时候记录优先于地图?我已经读过,当您多次重新构建同一张地图时,您应该支持记录(就像我在这种情况下一样)。这个逻辑合理吗?
【问题讨论】:
-
是什么让 Orc 攻击与 Troll 攻击有根本不同?
-
Orc V. Troll 可能不是最好的例子,但在某些情况下,特定实体的攻击方法会大不相同,以至于需要自己的独特计算。攻击也只是一个例子,会有许多共享方法在实现上有所不同。
-
是的,但它会附加到“类型”还是某些键的存在?
-
我认为按类型,兽人总是会以相同的方式执行攻击,这对于任何其他常见的“敌人”方法都是如此。
-
那么记录似乎没问题。如果您有其他调度标准,您可能需要研究多方法
标签: clojure functional-programming diamond-problem