Defmulti to defprotocol conversion

Can the code below be converted to use defprotocol

both 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))

      

+3


source to share


1 answer


Yes, you declare your functions in the protocol definition Shape

and then define your implementations in different 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)

      



Basically, it looks like OOP (but unchanged) if you're familiar with it.

One of the nice things about defmulti implementation for things like this, although you can often just serialize and deserialize your maps and use them as they are, without having to repeat them in a specific record class.

+4


source







All Articles