java - Clojure:是否可以继承用 :gen-class 定义的类的状态?

标签 java oop clojure functional-programming clojure-java-interop

我正在尝试研究一些以 Clojure 作为工作语言的 Java 库。该库(与 Java 中的通常情况一样)非常面向对象,并且需要客户端代码中的类层次结构。我定义了一个从库类继承的类,其中包含一些附加方法,并将数据作为可变字典存储在 state 字段中:

(:gen-class
   :name my-project.my-parent-class.MyParentClass
   :extends com.example.library.LibraryClass
   :methods [[setSomeData [com.example.library.LibraryType] void]]
   :exposes-methods {libraryMethodOne parentLibraryMethodOne
                     libraryMethodTwo parentLibraryMethodTwo}
   :init init
   :state state))

(defmacro set-field!
  [this key value]
  `(dosync (alter (.state ~this) assoc ~key ~value)))

(defmacro get-field
  [this key]
  `(@(.state ~this) ~key))

(defn -init []
  [[]
   (ref {:library-object-one (LibraryObjectOne.)
         :library-object-two (LibraryObjectTwo.)})])

(defn -setSomeData [this t]
  (.setSomething (get-field this :library-object-one) t)

… ; (library methods overriding here)

然后我创建了一个从我的 MyParentClass 继承的子类:

(:gen-class
   :name my-project.my-child-class.ChildClass
   :extends my-project.my-parent-class.MyParentClass
   :exposes-methods {libraryMethodOne myParentClassMethodOne}
   :init init
   :state state))

(defn -init []
  [[] (ref {})])
…

但是当我为 - 中的 ChildClass 实例调用 (get-field this :library-object-one) 宏时,出现空指针异常setSomeData 方法 — :state 定义的字段不会被继承,并且字典中没有键 :library-object-one

快速而肮脏的修复是在子类中重新定义 -init 函数,如下所示:

(defn -init []
  [[] (ref {:library-object-one (LibraryObjectOne.)
            :library-object-two (LibraryObjectTwo.)})])

(即从父类复制初始化代码)。但这严重违反了 DRY 原则。有没有办法从父类继承状态?

据我了解,这根本不是惯用的 Clojure,而是对 :gen-class API 的滥用,该 API 仅为了互操作性目的而提供。也许我不应该使用继承,而必须以某种非 OOP 方式实现多态性(例如,通过修改存储在状态字典中的函数和值)。如果这是真的,我在哪里可以看到这种方法的好例子?

最佳答案

您不必为子类提供 :state。如果不这样做,它只会调用父级的方法。

(ns my-project.classes)

(gen-class
  :name my_project.my_parent_class.MyParentClass
  :init init
  :state state)

(defn -init []
      [[]
       (ref {:library-object-one "foo"
             :library-object-two "bar"})])

(gen-class
  :name my_project.my_child_class.ChildClass
  :extends my_project.my_parent_class.MyParentClass)

以及调用命名空间:

(ns my-project.core
  (:import (my_project.my_child_class ChildClass))
  (:gen-class))

(defn -main [& args]
  (let [inst (ChildClass.)]
    (println @(.state inst))))

打印:

{:library-object-one foo, :library-object-two bar}

关于java - Clojure:是否可以继承用 :gen-class 定义的类的状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53171063/

相关文章:

java - 是否可以播放来自蓝牙的流式声音?

java - 如何为java swing应用程序设置图标?

java - 在调用 super 构造函数之前无法引用 'method'

clojure - clojure.core.reducers/reduce 的目的是什么?

string - 如何将数字字符串转换为数字(十进制)和数字到字符串

java - 八叉树堆栈溢出错误

java - 通过 java 将文件从 Linux 服务器中的一个位置复制到另一个位置的最佳方法

javascript - 如何从 Javascript 中的参数访问对象内的对象?

java - 应用架构问题

clojure - 从 Clojure 中的文件打印和阅读列表