Clojure中面向对象的编程方式,Multimethods和hierarchy

clojure回避了传统的面向对象式方法,每一个新的情况都创建一个数据类型。clojure倾向于创建一个大的方法库,方法库中只有一个小的类型集合。然而,clojure充分认识到运行时多态在实现灵活的和可扩展的架构的优势。clojure通过Multimethods来实现复杂的运行时多态,该系统支持调度一个或多个参数的类型、值、属性和元数据以及它们之间的关系。

clojure的multimethods由一个dispatching函数和一个或多个方法组成。当multimethod被定义时,使用defmulti,一个dispatching方法必须被提供。这个函数将要作为参数被提供给multimethod,目的是为了产生dispatching值。multimethod这时尝试寻找关联dispatching值或者从dispatching值派生的方法,如果一个函数被defmethod定义,这个函数将被调用。如果找不到的会,则会寻找默认的dispatching值,然后调用它。如果还找不到的话,就会报错。

multimethod的api有

  • defmulti创建新的multimethods
  • defmethod创建和设置一个新的方法,并关联一个dispatching-value
  • remove-method移除一个关联dispatching-value的方法
  • prefer-method创建一个可能会出现歧义时调用函数的顺序

派生是有java的继承或者clojure的ad hoc hierarchy系统决定的。hierarchy系统支持派生关系在两个名称之间,或类和名称之间。derive方法创建这些关系和isa!方法测试他们的关系。

您可以定义与 (派生子父级) 的hierarchy关系。子项和父项可以是符号或关键字,并且必须限定在命名空间

; 定义两个元素的关系
(derive ::rect ::shape)
(derive ::square ::rect)
; 返回::rect的父级
; #{:user/shape}
(parents ::rect)
; 返回::square的祖先集合
; #{:user/rect :user/shape}
(ancestors ::square)
; 返回::shape的子孙集合
; #{:user/rect :user/square}
(descendants ::shape)
; 测试两个元素的关系`
; true
(isa? ::square ::shape)
; true
(isa? String Object)

(derive ::rect ::shape)

; 消除歧义
(defmulti bar (fn [x y] [x y]))
(defmethod bar [::rect ::shape] [x y] :rect-shape)
(defmethod bar [::shape ::rect] [x y] :shape-rect)

(bar ::rect ::rect)
;-> Execution error (IllegalArgumentException) at user/eval152 (REPL:1).
;   Multiple methods in multimethod 'bar' match dispatch value:
;   [:user/rect :user/rect] -> [:user/shape :user/rect]
;   and [:user/rect :user/shape], and neither is preferred

(prefer-method bar [::rect ::shape] [::shape ::rect])
(bar ::rect ::rect)
;-> :rect-shape

最后来一段clojure实现的面向对象的数据结构

这段代码需要注意的是:Shape也是一个函数,返回一个Map中的键为:Shape的值

(defmulti area :Shape)
(defn rect [wd ht] {:Shape :Rect :wd wd :ht ht})
(defn circle [radius] {:Shape :Circle :radius radius})
(defmethod area :Rect [r]
    (* (:wd r) (:ht r)))
(defmethod area :Circle [c]
    (* (. Math PI) (* (:radius c) (:radius c))))
(defmethod area :default [x] :oops)
(def r (rect 4 13))
(def c (circle 12))
(area r)
;-> 52
(area c)
;-> 452.3893421169302
(area {})
;-> :oops

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值