是否可以转换以下代码,使其使用defprotocol和defrecord代替defmultiand 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))
Run Code Online (Sandbox Code Playgroud)
是的,你在协议定义中声明你的功能Shape,然后在您的各种记录实现定义的实现Square,Circle等等。
(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)
Run Code Online (Sandbox Code Playgroud)
从本质上讲,如果您熟悉,这就像OOP(但不可变)一样。
defmulti实现的好处是,您通常可以序列化和反序列化地图,并按原样使用它们,而不必将其变成特定的记录类。
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |