11

我们通常在java中使用builder模式,像这样:

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}))

所以,我的问题是,有没有一种优雅的方式来实现这一点?

4

5 回答 5

9

如果要构造一些 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 对象(使用它的 setter),你可以使用 Nicolas 建议的方法。

于 2012-09-28T05:15:02.737 回答
4

我通常会通过映射传递属性 - 这样做没有真正的问题,因为属性映射实际上只是 make-user 函数的一个参数。您还可以在 make-user 中做一些不错的事情,例如合并默认属性。

如果你真的想用构建器模式构建这样的映射,你可以使用线程宏来完成,如下所示:

(def john 
  (-> {}
    (assoc :name "John")
    (assoc :pass "1234")
    (assoc :vip true)
    (assoc :visible false)
    make-user))
于 2012-09-28T05:41:35.720 回答
4

改写

(def john (make-user {:name "John" :pass "1234" :vip true :visible false}))

分成多行:

(def john (make-user {:name "John" 
                      :pass "1234" 
                      :vip true 
                      :visible false}))
于 2012-09-28T09:26:43.630 回答
2

一个简单的方法是使用doto宏:

这是一个用一些值填充数组列表的示例:

(def al (doto (java.util.ArrayList.) (.add 11) (.add 3)(.add 7)))

Stuart 有一些关于如何在 Swing 中使用 doto 的完美示例。这里有一个面板:

(doto (JPanel.)
            (.setOpaque true)
            (.add label)
            (.add button))

这里有一个框架:

(doto (JFrame. "Counter App")
  (.setContentPane panel)
  (.setSize 300 100)
  (.setVisible true))
于 2012-09-28T05:05:01.533 回答
0

为了完整起见,没有人提到自动为您提供“构建器功能”的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}
于 2016-06-09T13:21:50.917 回答