【问题标题】:Clojure objects and higher-order functions for encapsulation用于封装的 Clojure 对象和高阶函数
【发布时间】:2011-05-15 14:03:32
【问题描述】:

这是我的earlier question 的后续。

我从阅读Let Over Lambda 中想到了一个奇怪的对象方案,并且可以认为没有优于协议,但想获得意见。我只是在探索使用高阶函数和封装。

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:get-first-name #(@first-name)
     :set-first-name #(dosync (ref-set first-name %1))
     :get-last-name #(@last-name)
     :set-last-name #(dosync (ref-set last-name %1))
     :get-age #(@age)
     :set-age #(dosync (ref-set age %1))}))

我可以这样使用对象:

(def fred (new-person "fred" "flintstone" 42))

并以这种方式检索访问器方法:

(fred :get-age)

但我不知道如何调用访问器。

创建的对象是线程安全的,因为“实例”变量的所有突变都发生在 STM 中。

更新:新的和改进的版本:

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:first-name 
        (fn
          ([] @first-name)
          ([val] (dosync (ref-set first-name val))))
     :last-name
        (fn
          ([] @last-name)
          ([val] (dosync (ref-set last-name val))))
     :age
        (fn
          ([] @age)
          ([val] (dosync (ref-set age val))))}))

【问题讨论】:

    标签: clojure encapsulation higher-order-functions


    【解决方案1】:

    也许不是 100% 回答您的问题,但您是否会尝试做对于 Clojure 来说不是很惯用的做法。 “标准”解决方案类似于:

    (defrecord Person [first-name last-name age])
    (def fred (Person. "fred" "flintstone" 42))
    (fred :age)
    

    看起来您正在将 OO 可变状态强制转换为 Clojure 的“对象”

    【讨论】:

      【解决方案2】:

      它与您的后续问题相同,将表格包装在另一组括号中。当内部形式返回函数时,它与返回函数的符号相同。规则是括号中的第一个形式将始终作为特殊形式、宏或函数查找。您需要像引用这样的东西来防止这种行为。

      user=> (fred :get-age)
      #<user$new_person$fn__531 user$new_person$fn__531@c4afc4>
      user=> ((fred :get-age))
      42
      

      和这个一样

      user=> (let [age-getter (fred :get-age)] (age-getter))
      42
      

      【讨论】:

        【解决方案3】:

        Clojure 的理念不是封装对记录字段本身的访问。封装应该发生在更高的级别上,例如在处理该记录的函数集中。见Clojure - datatypes

        信息的封装是愚蠢的,字段是公共的,使用协议/接口来避免依赖

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-16
          • 1970-01-01
          • 2015-06-25
          • 1970-01-01
          • 2010-12-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多