Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the clojure way to builder pattern?

We usually use builder pattern in java, like this:

UserBuilder userBuilder = new UserBuilder();
User John = userBuiler.setName("John")
                      .setPassword("1234")
                      .isVip(true)
                      .visableByPublic(false)
                      .build();

Some of the attributes have default value, and some haven't.

Passing attributes in a map may be a solution, but it makes the argument really longer:

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

So, my question is, is there a elegant way to achieve this?

like image 509
qiuxiafei Avatar asked Sep 28 '12 04:09

qiuxiafei


2 Answers

If you want to construct some clojure structure, you can use destructuring pattern in function arguments. You will then achieve the similar thing you have already wrote.

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

I doubt that you can do something in less code than this.

If you want to construct Java object (using its setters), you can use the approach Nicolas suggested.

like image 163
Vladimir Matveev Avatar answered Oct 27 '22 19:10

Vladimir Matveev


I would normally pass attributes in via a map - there's no real issue with doing this since the attribute map is really just one argument to the make-user function. You can also do nice stuff inside make-user like merge in default attributes.

If you really want to construct such a map with a builder pattern, you can do it with a threading macro as follows:

(def john 
  (-> {}
    (assoc :name "John")
    (assoc :pass "1234")
    (assoc :vip true)
    (assoc :visible false)
    make-user))
like image 24
mikera Avatar answered Oct 27 '22 19:10

mikera