我正在尝试使用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 {})])
…
但是,当我在(get-field this :library-object-one)
方法中为ChildClass
实例的-setSomeData
实例调用:state
宏时,会得到一个空指针异常-由:library-object-one
定义的字段不会被继承,在字典中没有键-init
。
快速而肮脏的修复程序是在子类中重新定义(defn -init []
[[] (ref {:library-object-one (LibraryObjectOne.)
:library-object-two (LibraryObjectTwo.)})])
函数,如下所示:
:gen-class
(即从父类复制初始化代码)。但这严重违反了DRY原则。有没有办法从父类继承状态?
我了解它根本不是惯用的Clojure,并且某种程度上滥用了state
API,该API仅出于互操作性目的而提供。也许我不应该使用继承,而必须以某种非OOP的方式实现多态(例如,通过修改存储在echo -e "ang?\r\n"> /dev/ttyUSB0
字典中的函数和值)。如果是真的,我在哪里可以看到这种方法的好例子?
答案 0 :(得分:2)
您不必为子类提供: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}