2012-09-28 25 views
10

我們通常在Java中使用生成器模式,就像這樣:什麼是構建模式的clojure方式?

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

所以,我的問題是,是否有一個優雅的方式來實現這一目標?

+1

Builder模式在我看來真的只是因爲缺少命名參數的解決辦法。初始化一組只能作爲位置參數的字段非常麻煩,而且以後很難閱讀,因此構建器模式。在一次函數調用中,地圖解構實現了相同的目標,Ankur建議將地圖分割成多行以保持可讀性。 –

回答

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對象(使用它的setters),你可以使用Nicolas建議的方法。

+2

爲了完整性,回答您的默認值,解構支持使用'or'設置默認值:'(defn make-user [&{:keys [name pass vip visible]:or {vip true}}]' – DanLebrero

+0

是的,如果變量的缺省值沒有在':or'映射中設置,並且在實際調用中沒有指定,它將變爲'nil'。 –

+1

你如何想象鵝口瘡(' - > '')可以代替'doto',因爲這些方法調用的返回值不是'this'? –

2

一個簡單的方法是使用doto宏:

下面是一個例子來填充一些值的數組列表:

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

斯圖爾特對如何使用多託與Swing some perfect examples。 這裏有一個小組:

(doto (JPanel.) 
      (.setOpaque true) 
      (.add label) 
      (.add button)) 
有框架

這裏:

(doto (JFrame. "Counter App") 
    (.setContentPane panel) 
    (.setSize 300 100) 
    (.setVisible true)) 
4

我通常會通過地圖傳遞屬性 - 這樣做並沒有真正的問題,因爲屬性映射實際上只是make-user函數的一個參數。你也可以在默認屬性中進行合併等好東西。

如果你真的想構建一個生成器模式這樣的地圖,你可以用一個線程宏觀如下做到這一點:

(def john 
    (-> {} 
    (assoc :name "John") 
    (assoc :pass "1234") 
    (assoc :vip true) 
    (assoc :visible false) 
    make-user)) 
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})) 
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} 
相關問題