tipos que programacion ejercicios ejemplos constructores java constructor

que - tipos de constructor java



Constructor de Java con argumentos grandes o enfoque de obtención/establecimiento de beans de Java (18)

No puedo decidir qué enfoque es mejor para crear objetos con un gran número de campos (10+) (todos obligatorios) el enfoque de constructor del que obtiene / establece. Constructor, al menos usted hace cumplir que todos los campos están establecidos. Java Beans es más fácil ver qué variables se están configurando en lugar de una gran lista. El patrón del constructor NO parece adecuado aquí ya que todos los campos son obligatorios y el constructor requiere que usted coloque todos los parámetros obligatorios en el constructor del constructor.

Gracias: D


¿Hay variaciones de la clase que podrían tomar menos argumentos, o hay solo uno y tiene diez propiedades?

¿Se supone que el objeto es inmutable?

Personalmente, no veo nada malo con los grandes constructores, especialmente si solo hay un constructor, y todas las propiedades también son definitivas.


¿Pueden sus campos ser combinados en un objeto intermedio? Por ejemplo, si está pasando 10 campos que describen a una persona, cree un objeto PersonInfo para pasar esos datos. Personalmente prefiero pasar todos los campos obligatorios al crear una instancia del objeto. De esa manera, no terminas con un objeto a medio hornear que inevitablemente será usado y abusado.


Diez argumentos para un constructor es mucho. Pensaría seriamente si todos son necesarios y algunos de ellos no tendrían sentido combinarlos en objetos lógicos. Si realmente hay diez datos requeridos distintos, entonces el constructor debe contener diez campos.


El mejor enfoque (imho) es usar algún tipo de constructor:

MyClass a = new MyClassBuilder().blah("blah").foo("foo").doStuff().toMyClass();

donde MyClass sigue siendo immutable pero tiene una creación mucho más legible que un constructor con 10 argumentos.

Esto también se llama una interfaz fluida . Josh Bloch se refiere a esto en Java efectiva .


En mi humilde opinión, debe pasar todo lo necesario para que un objeto sea válido de acuerdo con su lógica de negocios en el constructor.

Si la lista de argumentos es larga, puede crear un objeto que contenga los argumentos y pasarlo.


En su libro Code Complete , Steve McConnell argumenta que ningún procedimiento debería tener más de un máximo de 6, quizás 7 argumentos. La mayoría de estas afirmaciones no son solo su opinión, sino que están respaldadas por estudios, por ejemplo, las tasas de error relacionadas con la estructura del código.

El código limpio de Robert Martin va incluso más allá: recomienda 1 o 2 argumentos, mientras que 3 ya se considera un "olor a código". Personalmente, creo que Clean Code es un poco extremo en algunos lugares, pero en general presenta algunos buenos argumentos.

"Un montón de parámetros" (por muchos que sean) refleja un diseño de "fregadero de cocina" con muchos pensamientos y poca estructura. También hace que el mantenimiento sea más difícil y propenso a errores; Por lo menos, hace que el código sea difícil de leer.

Todo esto hace que haya buenas razones para pensar en reducir el número de parámetros. Otras respuestas han ofrecido algunas sugerencias prácticas.


Es una cuestión de diseño sin duda. Tienes que pesar la legibilidad con facilidad. Un constructor de diez argumentos es más fácil, pero puede o no ser más legible / mantenible. También tiene menos llamadas a métodos para activar y desactivar la pila de llamadas. Establecer diez valores distintos a través de los configuradores es un poco más legible y explícito. No es necesariamente "más fácil" (aunque podría argumentar en ambos sentidos), y agrega más llamadas de método para activar y desactivar la pila de llamadas.

Pero aquí hay algunos puntos más para pensar. Incluso con un constructor de diez argumentos, puede hacer que un programador elija pasar un nulo, un espacio en blanco, un falso o un cero (según el objeto o la primitiva), que puede o no ser lo que pretendía. Su única forma de controlar esto sería lanzar una excepción en el constructor. ¿Es esto lo que realmente quieres hacer? ¿Es este el comportamiento que esperas?

Por supuesto, al establecer cada variable por separado a través de los establecedores, es posible que no pueda saber cuándo está o no ha terminado de construir el objeto. Aquí es donde el patrón Builder discutido anteriormente ayudaría. Haga que cree el objeto, establezca los valores y luego valide que todos estén configurados. Si falta algo, porque un programador decidió no pasar algo, entonces usted está protegido. Tu clase no tiene que hacer más de lo que se supone. (Después de todo, es importante pensar en quién podría estar usando tu clase algún día. Es posible que no entiendan tu intención, a pesar de todo el gran Javadoc en el mundo).

Por último, le preguntaría si hay algo que deba omitir. Porque si ciertas cosas pueden ser predeterminadas, entonces puede establecerlas en valores predeterminados en el nivel de clase, o configurarlas en predeterminadas en el constructor (dependiendo de sus ideales de programación y que considere que son más específicos y ayudan con el comportamiento de su objeto) . Entonces, podría potencialmente "preestablecer" ciertos campos y solo tendrá que anularlos a través de los configuradores manualmente o a través de un Generador.

De nuevo, tienes que decidir estas cosas tú mismo. Pero probablemente lo más importante de todo esto es la consideración de la legibilidad por encima de la eficiencia para hacer que el código sea más fácil de mantener, y la creación de API y comportamientos que los programadores que vienen después no podrán abusar. Anticipe la protección contra el abuso en su diseño, cualquiera que sea su uso.


Esto es bastante difícil de responder en abstracto. Lo que realmente se necesita hacer es mirar esos diez parámetros y ver cuáles son. Veo estas como las preguntas clave:

  • ¿Se pueden combinar algunos de ellos en objetos de "valor" de nivel superior? Por ejemplo, las variables X e Y se pueden combinar en un Punto. Tuvimos muchas situaciones como esta dentro de un programa de enrutamiento de carga donde todos los campos se modelaron como cadenas primitivas. La introducción de algunos conceptos de nivel superior realmente ayudó a hacerlo legible.
  • ¿Algunos de los parámetros pueden ser "predeterminados" para ciertos valores?
  • ¿Son realmente todos conceptos independientes, ortogonales? He trabajado en muchos sistemas y nunca he visto que esto sea cierto. Si no, hay algo que pensar sobre esto.


Evitaría constructores con gran cantidad de argumentos. Las clases con muchos argumentos en los constructores pueden ser difíciles de manejar. Imagínese si tiene una jerarquía de herencia con subclases, cada una con muchos argumentos en sus constructores. Cuánto trabajo sería si fuera necesario cambiar los argumentos de algunos de los niveles superiores.

Pasaría una interfaz a su contructor que podría cambiar sin romper el código, o usar el enfoque de Java y tener un constructor sin argumentos.


Mi primer pensamiento es comprobar si su modelo de encapsulación es correcto. Tener más de 10 campos obligatorios parece bastante y quizás tiene más sentido tener componentes más detallados en este escenario.

¿Algunos de estos campos / parámetros están relacionados? ¿Se pueden combinar en objetos que tengan sentido (por ejemplo x-coordinate y se combinan en un objeto Point etc.)


OMI, los constructores no forman una buena API al crear objetos, especialmente cuando el número de argumentos es grande y son del mismo tipo.

new Person(String, String, String, String); // what the?? this is what may // show up in IDEs

donde realmente significa Persona (nombre, apellido, nombre de pantalla, contraseña, (solo por ejemplo)

Como menciona Cletus, el patrón Builder con encadenamiento es bueno. Otra ventaja con un constructor es que, si los objetos son inmutables, el constructor puede devolver el mismo objeto (en este caso, puede tener un constructor privado de paquetes con 15 argumentos que solo el constructor conoce). Los constructores también pueden devolver cualquier subtipo de los objetos que construyen.

Otro enfoque que podría tomar es considerar el uso de un DSL interno. Pero esto solo tiene sentido si está creando objetos como configuraciones, consultas, etc. Vea si tener un DSL interno tiene sentido en su caso.

Tuvimos un problema similar en nuestro proyecto. Tuvimos que obtener ciertos valores de una puerta de entrada doméstica (nuestro producto). Soportaba un protocolo XML basado en consultas y solicitudes a través de http. Pero la creación del objeto de solicitud para enviar en la interfaz de usuario fue tediosa, ya que se configuraron los objetos de solicitud con los parámetros y filtros apropiados, etc.

Inicialmente, nuestro objeto de solicitud se veía así:

Request r = new Request("SET"); r.setAction("add"); // modify, add, delete r.setModuleName("NPWIFI"): r.addParameter(new Param("wifiAclMac", "aa:bb:cc:dd:ee:ff")); r.addParameter(new Param("wifiCommit", "commit")); r.setActionParam("wifiAclRowStatus") r.addFilter(new Filter(Type.EQUALS, "wifiInterface", "wl0")); r.addFilter(new Filter(Type.EQUALS, "wifiAclMac", "yourgateway")); Resonse r = gwSession.sendRequest(r);

Así que lo cambiamos en un DSL interno que tenía una sensación similar a SQL pero solo programática

Query q = DQL.add("wifiAclMac", "wifiCommit").into("NPWIFI").values ("aa:bb:cc:dd:ee:ff", "commit").withAp("wifiAclRowStatus") .where("wifiInterface").is("wl0") .and("wifiAclMac").is("aa:bb:cc:dd:ee:ff").end();

El objeto "generador de consultas" de DQL hizo todo el proceso de validación y también demostró ser muy conveniente de usar.

Los constructores y los DSL son un medio elegante y poderoso para crear y construir objetos, pero vea qué tiene sentido en su caso.


Podría considerar usar un patrón de constructor , con el constructor asegurándose de que todos los campos estén al menos configurados en valores predeterminados razonables. Consulte el enlace para la implementación, pero terminaría con una llamada que se parece a algo como:

Widget widge = new Widget.Builder(). manufacturer("333").serialNumber("54321").build();


Realmente depende de la clase específica. ¿Debería ser inmutable? ¿Es un objeto de valor simple sin ningún comportamiento? ¿Asignará este objeto de valor a los parámetros del servicio web oa una base de datos relacional? ¿Vas a serializarlo? (Algunas de esas cosas necesitan un constructor por defecto). ¿Puedes contarnos un poco más sobre el objeto?


Recomendaría que consideres el patrón de construcción en tal caso. Se le garantiza que obtendrá un objeto válido, sin tener solo una gran lista de parámetros.

El OP se actualizó para rechazar el patrón del constructor, pero parece estar basado en un malentendido. El hecho de que exista el patrón Builder no elimina la aplicación de todos los parámetros.

Considere el siguiente objeto:

public class SomeImmutableObject { private String requiredParam1; private String requiredParam2; //etc. private SomeImmutableObject() { //cannot be instantiated outside the class } public static class Builder { private SomeImmutableObject instance; public Builder() { instance = new SomeImmutableObject(); public Builder setParameter1(String value) { instance.requiredParam1 = value; return this; } //etc for each parameter. public SomeImmutableObject build() { if (instance.requiredParam1 == null || instance.requiredParam2 == null /*etc*/) throw new IllegalStateException("All required parameters were not supplied."); return instance; } } }

Tenga en cuenta que puede lograr básicamente lo mismo haciendo que los campos sean privados y colocando el generador en el mismo paquete.

Y si por alguna razón no puede hacer eso, aún puede tener el constructor con los 10 parámetros, y luego hacer que Builder sea lo único que llame a ese constructor, de modo que sea una API más fácil de usar.

Así que para todos los requisitos indicados, el patrón Builder funciona bien. El hecho de que se requieran los 10 parámetros no descalifica el patrón del generador en absoluto. Si hay alguna otra necesidad que el patrón no satisface, por favor, elabore.

Edición: El OP agregó un comentario (hace bastante tiempo, pero acabo de recibir un voto a favor de esta pregunta, así que solo lo vi ahora) con una pregunta interesante: ¿Cómo validar una primitiva en un momento posterior?

Hay algunas maneras de evitar ese problema, incluido un booleano de protección, pero mi forma preferida sería usar un objeto Doble como el siguiente:

private Double doubleForPrimitive; public Builder setDouble(double d) { doubleForPrimitive = d; } public SomeImmutableObject build() { if(doubleForPrimitive != null) { instance.doubleParam = doubleForPrimitive; } else { throw new IllegalArgumentExcepion("The parameter double was not provided"); } //etc. }

Debe tenerse en cuenta que si necesita una verdadera inmutabilidad segura para subprocesos teniendo todos los campos del objeto inmutable como final, esto requiere más repetición (almacenar las variables dentro del constructor y pasarlas a un constructor privado del objeto inmutable), pero El enfoque sigue siendo limpio desde el punto de vista del código del cliente.


Si todos los parámetros son de hecho obligatorios, entonces no veo ninguna razón para no usar un constructor. Sin embargo, si ese no es el caso, entonces usar un constructor parece ser el mejor enfoque.
En mi opinión, confiar solo en los configuradores es la peor solución, ya que no hay nada que obligue a que se establezcan todas las propiedades obligatorias. Por supuesto, si está utilizando el cableado de bean de Spring Framework u otra solución similar, entonces los de Java están perfectamente bien, ya que puede verificar después de la inicialización que todo está configurado.


Si todos los parámetros son realmente necesarios, y no está utilizando Spring para crear una instancia del bean, definitivamente iría con un constructor con 10 parámetros. Así queda claro que todos los parámetros son, de hecho, necesarios.

Si lo hace Spring (quizás ocasionalmente) para crear el bean, o si realmente no le gusta tener muchas variables temporales en el método que construye ese bean, también puede usar getters y setters. Si también implementa un método de validación para verificar si el objeto es correcto, no debería tener problemas.

El método de validación funciona mejor, sin embargo, si lo usas consistentemente; Tal vez por tener una interfaz válida. Encaja muy bien en un flujo de trabajo si es parte del estilo de programación. Si solo hay una o dos clases en las que se usa este paradigma, probablemente no valga la pena. Te olvidarás de llamar validate () de todos modos algún día, en algún lugar.

Si no está utilizando un enfoque de validación y no le gusta el constructor (aunque no sabría por qué, para eso es) siempre puede recurrir a los Constructores mencionados por los demás.

Por lo que vale; Si tiene 10 argumentos obligatorios y no puede agruparlos lógicamente, puede que haya mezclado muchos conceptos diferentes en una clase; en ese caso, podría ser incluso mejor echar un vistazo a su diseño y refactorizarlo un poco.


Yo implementaría el patrón de construcción de esta manera:

package so1632058; public class MyClass { private final String param1; private final String param2; MyClass(Builder builder) { this.param1 = builder.param1; this.param2 = builder.param2; } public String getParam1() { return param1; } public String getParam2() { return param2; } @SuppressWarnings("hiding") public static final class Builder { String param1; String param2; public Builder param1(String param1) { this.param1 = param1; return this; } public Builder param2(String param2) { this.param2 = param2; return this; } public MyClass toMyClass() { return new MyClass(this); } } }

Y luego tener el siguiente código para usarlo:

package so1632058; public class Main { public static void main(String[] args) { MyClass.Builder builder = new MyClass.Builder(); builder.param1("p1").param2("p2"); MyClass instance = builder.toMyClass(); instance.toString(); } }

Algunas notas:

  • No hay métodos con muchos parámetros.
  • La comprobación adicional se puede hacer en el constructor MyClass .
  • Hice la visibilidad del constructor en todo el paquete para evitar la advertencia de "acceso sintético".
  • Lo mismo para los campos de instancia del constructor.
  • La única forma de construir una instancia de MyClass es a través del Builder .