I'm having a hard time deciding when using defrecord
is the right choice and more broadly if my use of protocols on my records is semantic clojure and functional.
In my current project I'm building a game that has different types of enemies that all have the same set of actions, where those actions might be implemented differently.
Coming from an OOP background, I'm tempted to do something like:
(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
This looks like it makes sense on the surface. I want every enemy to always have an attack method, but the actual implementation of that should be able to vary on the particular enemy. Using the extend-protocol
I'm able to create efficient dispatch of the methods that vary on my enemies, and I can easily add new enemy types as well as change the functionally on those types.
The problem I'm having is why should I use a record over a generic map? The above feels a bit to OOP to me, and seems like I'm going against a more functional style. So, my question is broken into two:
- Is my above implementation of records and protocols a sound use case?
- More generically, when is a record preferred over a map? I've read you should favor records when you're re-building the same map multiple times (as I would be in this case). Is that logic sound?