Какой способ clojure для построения шаблона?
Обычно мы используем шаблон builder в 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}))
Итак, мой вопрос: есть ли элегантный способ достичь этого?
Ответы
Ответ 1
Если вы хотите построить некоторую структуру 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 (используя его сеттеры), вы можете использовать подход, предложенный Николасом.
Ответ 2
Я бы обычно передавал атрибуты через карту - нет реальной проблемы с этим, так как карта атрибутов на самом деле является всего лишь одним аргументом функции make-user. Вы также можете делать приятные вещи внутри make-user, например merge в атрибутах по умолчанию.
Если вы действительно хотите построить такую карту с шаблоном построителя, вы можете сделать это с помощью макроса с потоком следующим образом:
(def john
(-> {}
(assoc :name "John")
(assoc :pass "1234")
(assoc :vip true)
(assoc :visible false)
make-user))
Ответ 3
Переписать
(def john (make-user {:name "John" :pass "1234" :vip true :visible false}))
на несколько строк:
(def john (make-user {:name "John"
:pass "1234"
:vip true
:visible false}))
Ответ 4
Простым способом является использование макроса doto:
Вот пример, чтобы заполнить список массивов некоторыми значениями:
(def al (doto (java.util.ArrayList.) (.add 11) (.add 3)(.add 7)))
Стюарт некоторые прекрасные примеры о том, как использовать doto с Swing.
Здесь с панелью:
(doto (JPanel.)
(.setOpaque true)
(.add label)
(.add button))
Здесь с рамкой:
(doto (JFrame. "Counter App")
(.setContentPane panel)
(.setSize 300 100)
(.setVisible true))
Ответ 5
Для полноты, никто не упомянул defrecord, который автоматически дает вам функции "builder"
(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}