Reputation: 7679
Is it possible to convert the below code so it uses defprotocol
and defrecord
instead of defmulti
and defmethod
?
(defmulti test-multimethod (fn [keyword] keyword))
(defmethod test-multimethod :foo [a-map]
"foo-method was called")
(defmethod test-multimethod :bar [a-map]
"bar-method was called")
(defmulti perimeter (fn [shape] (:shape-name shape)))
(defmethod perimeter :circle [circle]
(* 2 Math/PI (:radius circle)))
(defmethod perimeter :rectangle [rectangle]
(+ (* 2 (:width rectangle)) (* 2 (:height rectangle))))
(def some-shapes [{:shape-name :circle :radius 4}
{:shape-name :rectangle :width 2 :height 2}])
(defmulti area (fn [shape] (:shape-name shape)))
(defmethod area :circle [circle]
(* Math/PI (:radius circle) (:radius circle)))
(defmethod area :rectangle [rectangle]
(* (:width rectangle) (:height rectangle)))
(defmethod perimeter :square [square]
(* 4 (:side square)))
(defmethod area :square [square]
(* (:side square) (:side square)))
(def more-shapes (conj some-shapes
{:shape-name :square :side 4}))
(for [shape more-shapes] (perimeter shape))
(for [shape more-shapes] (area shape))
Upvotes: 3
Views: 157
Reputation: 10781
Yes, you declare your functions in the protocol definition Shape
, and then you define your implementations in your various record implementations Square
, Circle
, etc.
(defprotocol Shape
(area [this])
(perimeter [this]))
(defrecord Square [side] Shape
(area [this] (* (:side this) (:side this)))
(perimeter [this] (* 4 (:side this))))
(defrecord Rect [w l] Shape
(area [this] (* (:l this) (:w this)))
(perimeter [this] (+ (:l this) (:l this) (:w this) (:w this))))
(def s (->Square 4))
(def r (->Rect 2 5))
(map area [s r]) ; '(16 10)
(map :side [s r]) ; '(4 nil)
(map :l [s r]) ; '(nil 5)
Essentially this is just like OOP (but immutable) if you're familiar with that.
One nice thing about the defmulti implementation for things like this though, are you can often just serialize and deserialize your maps and use them as-is, without having to reify them into the specific record class.
Upvotes: 5