Ocasionalmente, tenemos que escribir métodos que reciben muchos argumentos, por ejemplo:
public void doSomething(Object objA , Object objectB ,Date date1 ,Date date2 ,String str1 ,String str2 )
{
}
Cuando me encuentro con este tipo de problema, a menudo encapsulo argumentos en un mapa.
Map<Object,Object> params = new HashMap<Object,Object>();
params.put("objA",ObjA) ;
......
public void doSomething(Map<Object,Object> params)
{
// extracting params
Object objA = (Object)params.get("objA");
......
}
Esta no es una buena práctica, encapsular parámetros en un mapa es una pérdida total de eficiencia. Lo bueno es que la firma limpia es fácil de agregar otros parámetros con la menor cantidad de modificaciones. ¿Cuál es la mejor práctica para este tipo de problema?
java
performance
parameters
parameter-passing
Aserrador
fuente
fuente
Usar un mapa con claves de cadena mágicas es una mala idea. Pierde la comprobación del tiempo de compilación y no está claro cuáles son los parámetros necesarios. Necesitaría escribir documentación muy completa para compensarlo. ¿Recordará en unas semanas cuáles son esas cadenas sin mirar el código? ¿Y si cometiste un error tipográfico? ¿Utiliza el tipo incorrecto? No lo sabrá hasta que ejecute el código.
En su lugar, use un modelo. Cree una clase que será un contenedor para todos esos parámetros. De esa forma mantendrá la seguridad de tipos de Java. También puede pasar ese objeto a otros métodos, ponerlo en colecciones, etc.
Por supuesto, si el conjunto de parámetros no se usa en otro lugar o no se transmite, un modelo dedicado puede ser excesivo. Hay que lograr un equilibrio, así que use el sentido común.
fuente
Si tiene muchos parámetros opcionales, puede crear una API fluida: reemplace el método único con la cadena de métodos
exportWithParams().datesBetween(date1,date2) .format("xml") .columns("id","name","phone") .table("angry_robots") .invoke();
Con la importación estática puede crear API internas fluidas:
fuente
Se llama "Introducir objeto de parámetro". Si se encuentra pasando la misma lista de parámetros en varios lugares, simplemente cree una clase que los contenga todos.
XXXParameter param = new XXXParameter(objA, objB, date1, date2, str1, str2); // ... doSomething(param);
Incluso si no se encuentra pasando la misma lista de parámetros con tanta frecuencia, esa fácil refactorización seguirá mejorando la legibilidad de su código, lo cual siempre es bueno. Si miras tu código 3 meses después, será más fácil comprender cuándo necesitas corregir un error o agregar una función.
Es una filosofía general, por supuesto, y como no ha proporcionado ningún detalle, tampoco puedo darle un consejo más detallado. :-)
fuente
XXXParameter param = new XXXParameter();
disponible y luego usarXXXParameter.setObjA(objA)
; etc ...Primero, intentaría refactorizar el método. Si usa tantos parámetros, puede que sea demasiado largo. Desglosarlo mejoraría el código y reduciría potencialmente la cantidad de parámetros para cada método. También es posible que pueda refactorizar toda la operación en su propia clase. En segundo lugar, buscaría otras instancias en las que esté usando el mismo (o superconjunto) de la misma lista de parámetros. Si tiene varias instancias, es probable que indique que estas propiedades van juntas. En ese caso, cree una clase para contener los parámetros y utilícela. Por último, evaluaría si la cantidad de parámetros hace que valga la pena crear un objeto de mapa para mejorar la legibilidad del código. Creo que esta es una llamada personal: hay problemas en cada sentido con esta solución y dónde está el punto de compensación puede diferir. Para seis parámetros probablemente no lo haría. Para 10 probablemente lo haría (si ninguno de los otros métodos funcionara primero).
fuente
Esto suele ser un problema al construir objetos.
En ese caso, use el patrón de objetos del constructor , funciona bien si tiene una gran lista de parámetros y no siempre los necesita todos.
También puede adaptarlo a la invocación de métodos.
También aumenta mucho la legibilidad.
public class BigObject { // public getters // private setters public static class Buider { private A f1; private B f2; private C f3; private D f4; private E f5; public Buider setField1(A f1) { this.f1 = f1; return this; } public Buider setField2(B f2) { this.f2 = f2; return this; } public Buider setField3(C f3) { this.f3 = f3; return this; } public Buider setField4(D f4) { this.f4 = f4; return this; } public Buider setField5(E f5) { this.f5 = f5; return this; } public BigObject build() { BigObject result = new BigObject(); result.setField1(f1); result.setField2(f2); result.setField3(f3); result.setField4(f4); result.setField5(f5); return result; } } } // Usage: BigObject boo = new BigObject.Builder() .setField1(/* whatever */) .setField2(/* whatever */) .setField3(/* whatever */) .setField4(/* whatever */) .setField5(/* whatever */) .build();
También puede poner la lógica de verificación en los métodos Builder set .. () y build ().
fuente
final
? Esto es lo principal que me impide escribir funciones de ayuda. Supongo que puedo hacer que los campos sean privados y asegurarme de no modificarlos incorrectamente en el código de esa clase, pero espero algo más elegante.Hay un patrón llamado objeto de parámetro .
La idea es usar un objeto en lugar de todos los parámetros. Ahora, incluso si necesita agregar parámetros más tarde, solo necesita agregarlos al objeto. La interfaz del método sigue siendo la misma.
fuente
Podría crear una clase para almacenar esos datos. Sin embargo, debe ser lo suficientemente significativo, pero mucho mejor que usar un mapa (Dios mío).
fuente
Code Complete * sugiere un par de cosas:
* Primera edición, sé que debería actualizar. Además, es probable que algunos de estos consejos hayan cambiado desde que se escribió la segunda edición cuando OOP comenzaba a ser más popular.
fuente
Una buena práctica sería refactorizar. ¿Qué pasa con estos objetos que significa que deben pasarse a este método? ¿Deberían encapsularse en un solo objeto?
fuente
Usar un mapa es una forma sencilla de limpiar la firma de la llamada, pero luego tiene otro problema. Debe mirar dentro del cuerpo del método para ver qué espera el método en ese mapa, cuáles son los nombres de las claves o qué tipos tienen los valores.
Una forma más limpia sería agrupar todos los parámetros en un objeto bean, pero eso aún no soluciona el problema por completo.
Lo que tienes aquí es un problema de diseño. Con más de 7 parámetros para un método comenzarás a tener problemas para recordar qué representan y qué orden tienen. A partir de aquí, obtendrá muchos errores simplemente llamando al método en el orden de parámetros incorrecto.
Necesita un mejor diseño de la aplicación, no una buena práctica para enviar muchos parámetros.
fuente
Cree una clase de frijol, establezca todos los parámetros (método setter) y pase este objeto de frijol al método.
fuente
Mire su código y vea por qué se pasan todos esos parámetros. A veces es posible refactorizar el método en sí.
Usar un mapa deja su método vulnerable. ¿Qué pasa si alguien que usa su método escribe mal el nombre de un parámetro o publica una cadena donde su método espera un UDT?
Definir un objeto de transferencia . Le proporcionará verificación de tipo como mínimo; incluso puede ser posible que realice alguna validación en el punto de uso en lugar de dentro de su método.
fuente
Esto suele ser una indicación de que su clase tiene más de una responsabilidad (es decir, su clase hace DEMASIADO).
Ver el principio de responsabilidad única
para mas detalles.
fuente
Si está pasando demasiados parámetros, intente refactorizar el método. Tal vez está haciendo muchas cosas que se supone que no debe hacer. Si ese no es el caso, intente sustituir los parámetros con una sola clase. De esta manera, puede encapsular todo en una instancia de una sola clase y pasar la instancia y no los parámetros.
fuente
Yo diría que siga con la forma en que lo hizo antes. La cantidad de parámetros en su ejemplo no es mucha, pero las alternativas son mucho más horribles.
Mapa: está el aspecto de la eficiencia que mencionaste, pero el problema más grande aquí es:
cosa ... ¿Tiene javadocs que indique exactamente qué claves y
valores se utilizan? Si lo hace (lo cual es genial), entonces tener muchos parámetros tampoco es un problema.
Objetos de envoltura: esto solo mueve el problema ya que necesita llenar el objeto de envoltura en primer lugar, en lugar de directamente a su método, será al constructor del objeto de parámetro. Determinar si mover el problema es apropiado o no depende de la reutilización de dicho objeto. Por ejemplo:
No lo usaría: solo se usaría una vez en la primera llamada, por lo que ¿mucho código adicional para tratar con 1 línea ...?
Puede usarlo: aquí, puede hacer un poco más. Primero, puede factorizar los parámetros para 3 llamadas a métodos. también puede realizar otras 2 líneas en sí mismo ... por lo que se convierte en una variable de estado en cierto sentido ...
La otra cosa que la gente se olvida de considerar es el papel del IDE en todo esto. Cuando los métodos tienen parámetros, los IDE generan la mayor parte del código por usted, y las líneas rojas le recuerdan lo que necesita suministrar / configurar. Cuando usa la opción 3 ... pierde esto por completo. Ahora depende del programador hacerlo bien, y no hay señales durante la codificación y el tiempo de compilación ... el programador debe probarlo para averiguarlo.
Además, las opciones 2 y 3, si se adoptan de forma generalizada innecesariamente, tienen implicaciones negativas a largo plazo en términos de mantenimiento debido a la gran cantidad de código duplicado que genera. Cuanto más código hay, más hay que mantener, más tiempo y dinero se gasta en mantenerlo.
fuente