2009-05-06 9 views
24

Los siguientes son los dos enfoques:¿Constructor con todas las propiedades de clase o constructor predeterminado con setters?

  • constructor con todas las propiedades de la clase

Pros: Tengo que poner un número exacto de los tipos de parámetros por lo que si hago un error el compilador me advierte (por cierto, ¿hay alguna manera de evitar el problema de haber cambiado erróneamente dos enteros en la lista de parámetros?)

Contras: si tengo muchas propiedades, la línea de creación de instancias puede ser muy larga y abarcar más de dos o más líneas

  • set y el constructor por defecto vacío

Pros: Puedo ver claramente lo que estoy estableciendo, por lo que si estoy haciendo algo mal me puedo identificar lo más pronto que estoy escribiendo (No puedo hacer el error anterior de cambiar dos variables del mismo tipo)

Contras: la instanciación de un objeto con muchas propiedades podría tomar varias líneas (no sé si esto es realmente una estafa) y si Me olvido de establecer una propiedad, el compilador no dice nada.

¿Qué vas a hacer y por qué? ¿Conoce algún patrón de luz (considere que debe usarse cada vez que se crea una instancia de un objeto con más de 7 propiedades) para sugerir? Pregunto esto porque tiendo a detestar los grandes constructores donde no puedo descubrir rápidamente dónde está la variable que estoy buscando, por otro lado encuentro que "establecer todas las propiedades" es vulnerable a la falta de algunas de las propiedades .

dude en mis suposiciones argumento en favor y en contra, ya que son la única mina de pensamientos :)

Actualizar - una pregunta que me he encontrado que está relacionado con esto: Building big, immutable objects without using constructors having long parameter lists

Respuesta

20

Puede consultar el patrón del generador defendido por Joshua Bloch, y descrito en Java efectivo. Hay una presentación con los puntos principales en http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf; sin duda podrías desenterrar una mejor referencia.

Básicamente, tiene otra clase, probablemente una clase interna, que proporciona métodos con el nombre de las propiedades que se establecen, y que devuelve el generador original para que pueda encadenar llamadas. Hace un pedazo de código bastante legible.

Por ejemplo, supongamos que tengo un simple Message con algunas propiedades. El código de cliente construir esto podría utilizar un constructor para preparar un Message de la siguiente manera:

Message message = new Message.Builder() 
    .sender(new User(...)) 
    .recipient(new User(...)) 
    .subject("Hello, world!") 
    .text(messageText) 
    .build(); 

Un fragmento de Message.Builder puede tener un aspecto similar al siguiente:

public class Builder { 

    private User sender = null; 
    // Other properties 

    public Builder sender(User sender) { 
     this.sender = sender; 
     return this; 
    } 
    // Methods for other properties 

    public Message build() { 
     Message message = new Message(); 
     message.setSender(sender); 
     // Set the other properties 
     return message; 
    } 

} 
+0

Gracias por el código explicativo –

+0

Los constructores son realmente agradables si tiene un objeto complejo. Puedo recomendarlo fuertemente –

+0

y el libro! Es realmente una lectura obligada para los programadores de Java - está disponible en O'Reilly Safari, que es donde yo la leo (tenemos la suscripción más pequeña) –

26

te has perdido la El mayor profesional de tener un constructor con muchos parámetros: te permite crear tipos inmutables.

La forma normal de la creación de tipos inmutables sin enorme maldad constructor es tener un tipo de ayuda - un constructor que mantiene los valores que usted desea en su objetivo final, a continuación, genera el objeto inmutable cuando estás Listo.

+0

¿No es un constructor la mejor estrategia de todos modos? – Uri

+0

Además, si el estado de su objeto no puede ejecutarse sin que se establezcan las propiedades, obligue al usuario a establecerlas pasando por el constructor. –

+0

@Uri: el patrón del constructor está por encima del IMO superior si solo tiene algunas propiedades. –

6

La investigación académica reciente (CMU y Microsoft) sobre la usabilidad API sugiere que los constructores por defecto con los setters serían el camino a seguir en términos de usabilidad. Esto es de "Implicaciones de usabilidad de requerir parámetros de constructores Objects" de Jeff Stylos y Steven Clarke y fue presentado en la Conferencia Internacional sobre Ingeniería de Software:

Abstract: La facilidad de uso de las API es cada vez más importante a programador productividad. Con base en la experiencia con estudios de usabilidad de API específicas, se exploraron técnicas para estudiar la usabilidad de opciones de diseño comunes a muchas API. Se realizó un estudio comparativo para evaluar cómo los programadores profesionales usan las API con los parámetros requeridos en los constructores de los objetos en comparación con los constructores "predeterminados" sin parámetros. Se formuló la hipótesis de que los parámetros necesarios crearían API más utilizables y autodocumentadas guiando a los programadores hacia el uso correcto de los objetos y evitando errores.Sin embargo, en el estudio, se encontró que, contrariamente a lo esperado, los programadores preferían y eran más efectivos con las API que no requerían parámetros de constructor. El comportamiento de los participantes se analizó utilizando el marco de dimensiones cognitivas, y revelando que los parámetros constructor requeridos interfieren con las estrategias de aprendizaje comunes, causando un compromiso prematuro indeseable.

0

Hay otros aspectos también. Si desea poder hacer ciertas cosas con su clase en tiempo de diseño y no solo en tiempo de ejecución, por ejemplo, agregando su clase como un objeto en la Paleta de objetos (esto es Java usando Netbeans) necesita proporcionar un constructor sin argumento en para poder hacerlo

+0

Esta es una consideración importante: las herramientas ORM (por ejemplo, Hibernate, aunque no estoy seguro de si la última versión todavía lo hace) tienden a requerir setters accesibles y un constructor predeterminado. – hromanko

3

lo mencionas en tu mensaje, pero creo que este es un punto importante que merece más atención: a menos que cada parámetro de entrada es un tipo diferente, el gran problema de enormes constructores es que es muy fácil de transponer una pareja de variables El compilador es una red de seguridad no confiable, cometerá algunos errores, pero los que se deslizan serán mucho más difíciles de identificar y depurar. Especialmente porque la lista de entrada para un gran constructor es bastante opaca a menos que tengas la API abierta en otra ventana.

Los getters y setters son mucho más fáciles de depurar, especialmente si se establecen salvaguardas que arrojen una excepción de tiempo de ejecución si el objeto no está debidamente rellenado. Y soy un gran admirador de "fácil de depurar".

Antes de este hilo, nunca había escuchado sobre el patrón del Constructor que Rob menciona. Nunca lo usé yo mismo (obviamente), pero es condenadamente intrigante.

+0

¿Cómo protege un instituto que arroja una excepción de tiempo de ejecución si el objeto no está debidamente poblado? – mayu

0

También hay otras estrategias aquí. Antes de tratar de descubrir cómo manejar muchos parámetros, creo que es importante volver a visitar su diseño y ver si su clase está haciendo demasiado. Vea si puede agrupar algunos de los parámetros en una nueva clase y mover algún comportamiento a esa clase.

2

Prefiero tomar argumentos constructor, por las razones de inmutabilidad antes mencionadas.Si eso le da un constructor que toma muchos argumentos (digamos más de cuatro o más), ese es un olor a código para mí: algunos de esos argumentos deberían agruparse en sus propios tipos.

Por ejemplo, si tiene algo como esto:

class Contact 
{ 
    public Contact(string firstName, string lastName, string phoneNumber, 
     string street, string city, string state, int zipCode) { ... } 
} 

Me refactorearlo a:

class Contact 
{ 
    public Contact(Person person, PhoneNumber number, Address address) { ... } 
} 

class Person 
{ 
    public Person(string firstName, string lastName) { ... } 
} 

class PhoneNumber 
{ 
    public PhoneNumber(string digits) { ... } 
} 

class Address 
{ 
    public Address(string street, string city, string state, int zipCode) { ... } 
} 

demasiado grandes clases son un problema de diseño muy común en las bases de código de POO.

+0

¿cómo se maneja con zipCode opcional? –

+0

Sobrecarga el constructor de la dirección. – munificent

0

¿Quién dice que no puede hacer las dos cosas? Yo diría que las propiedades obligatorias van al constructor, las opcionales se manejan con setters. Por cierto, ¿quién dice que siempre necesitas un setter por propiedad? Si dos propiedades se unen conceptualmente, ¿por qué no configurarlas?

También me gusta el patrón Builder, pero la regla más importante es: siempre use su cerebro y encuentre el diseño que mejor se adapte al problema específico. No hay una solución única para todos.

Cuestiones relacionadas