我们通常在java中使用构建器模式,如下所示:
UserBuilder userBuilder = new UserBuilder();
User John = userBuiler.setName("John")
.setPassword("1234")
.isVip(true)
.visableByPublic(false)
.build();
某些属性具有默认值,而某些属性则没有。
在映射中传递属性可能是一种解决方案,但它会使参数变得更长:
(def john (make-user {:name "John" :pass "1234" :vip true :visible false}))
所以,我的问题是,有没有一种优雅的方式来实现这一目标?
如果你想构造一些clojure结构,你可以在函数参数中使用解构模式。然后,您将实现您已经写过的类似内容。
(defn make-user [& {:keys [name pass vip visible]}]
; Here name, pass, vip and visible are regular variables
; Do what you want with them
)
(def user (make-user :name "Name" :pass "Pass" :vip false :visible true))
我怀疑你能用比这更少的代码做一些事情。
如果你想构造Java对象(使用它的setters),你可以使用Nicolas建议的方法。
我通常会通过映射传递属性 - 这样做没有真正的问题,因为属性映射实际上只是make-user函数的一个参数。你也可以在make-user中做一些好事,比如在默认属性中合并。
如果你真的想用构建器模式构造这样的映射,你可以使用线程宏来完成,如下所示:
(def john
(-> {}
(assoc :name "John")
(assoc :pass "1234")
(assoc :vip true)
(assoc :visible false)
make-user))
(def john (make-user {:name "John" :pass "1234" :vip true :visible false}))
分为多行:
(def john (make-user {:name "John"
:pass "1234"
:vip true
:visible false}))
一个简单的方法是使用 doto 宏:
下面是使用一些值填充数组列表的示例:
(def al (doto (java.util.ArrayList.) (.add 11) (.add 3)(.add 7)))
Stuart有一些关于如何将doto与Swing一起使用的完美例子。这里有一个面板:
(doto (JPanel.)
(.setOpaque true)
(.add label)
(.add button))
这里有一个框架:
(doto (JFrame. "Counter App")
(.setContentPane panel)
(.setSize 300 100)
(.setVisible true))
为了完整起见,没有人提到 defrecord,它会自动为您提供"构建器函数"
(defrecord User [name pass vip visible])
(User. "John" "1234" true false)
;;=>#user.User{:name "John", :pass "1234", :vip true, :visible false}
(->User "John" "1234" true false)
;;=>#user.User{:name "John", :pass "1234", :vip true, :visible false}
(map->User {:name "John" :pass "1234" :vip true :visible false})
;;=>#user.User{:name "John", :pass "1234", :vip true, :visible false}