2012-09-28 74 views
10

Utilizamos generalmente Builder en Java, así:¿Cuál es la manera correcta de construir el patrón?

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

Algunos de los atributos tienen valor por defecto, y algunos no lo tienen.

atributos Pasando en un mapa puede ser una solución, pero hace que el argumento realmente ya:

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

lo tanto, mi pregunta es, ¿hay una manera elegante para lograr esto?

+1

La Builder es en mi opinión es sólo un trabajo en torno a la falta de parámetros con nombre. Inicializar un conjunto de campos que se distinguen solo como argumentos posicionales es extremadamente engorroso y muy difícil de leer más tarde, de ahí el patrón del constructor. La desestructuración de mapas logra los mismos objetivos en una sola invocación de función, ya que Ankur sugiere dividir un mapa en múltiples líneas para mantener la legibilidad. –

Respuesta

9

Si desea construir una estructura clojure, puede utilizar patrón de desestructuración en argumentos de la función. Luego logrará lo similar que ya ha escrito.

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

dudo que usted puede hacer algo en menos código que esto.

Si desea construir un objeto Java (utilizando sus ajustadores), puede usar el enfoque sugerido por Nicolas.

+2

Para completar, respondiendo sobre sus valores predeterminados, los valores predeterminados de la compatibilidad de desestructuración con 'o':' (defn make-user [& {: keys [name pass vip visible]: o {vip true}}] ' – DanLebrero

+0

Sí, usted re completamente a la derecha. También agregaría que si el valor predeterminado de la variable no se establece en el mapa ': o' y no se especifica en la llamada real, se convierte en' nil'. –

+1

¿Cómo te imaginas el tordo ('-> ') funcionaría en lugar de' doto', ya que el valor de retorno de esas llamadas al método no es 'this'? –

2

Una forma sencilla es utilizar el doto macro:

Aquí hay un ejemplo para rellenar una lista de arreglo con algunos valores:

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

Stuart tiene some perfect examples sobre cómo utilizar doto con Swing. Aquí con un panel:

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

aquí con un marco:

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

Normalmente paso los atributos en un mapa - no hay un problema real al hacerlo, ya que el mapa de atributos es realmente solo un argumento para la función make-user. También puedes hacer cosas agradables dentro de make-user como merge en los atributos por defecto.

Si realmente desea construir un mapa de este tipo con un Builder, puede hacerlo con una macro enhebrado de la siguiente manera:

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

reescritura

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

en varias líneas:

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

Para completar, nadie mencionó defrecord que le da "funciones constructor" automáticamente

(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} 
Cuestiones relacionadas