¿Está modificando un parámetro entrante un antipatrón? [cerrado]

54

Estoy programando en Java, y siempre hago conversores como este:

public OtherObject MyObject2OtherObject(MyObject mo){
    ... Do the conversion
    return otherObject;
}

En el nuevo lugar de trabajo, el patrón es:

public void MyObject2OtherObject(MyObject mo, OtherObject oo){
    ... Do the conversion
}

Para mí es un poco maloliente, ya que me acostumbré a no cambiar los parámetros entrantes. ¿Es esta alteración del parámetro entrante un antipattern o está bien? ¿Tiene algunos inconvenientes serios?

    
pregunta CsBalazsHungary 23.06.2014 - 13:53

8 respuestas

65

No es un antipatrón, es una mala práctica.

La diferencia entre un antipattern y una mera mala práctica se encuentra aquí: definición antipatrónica .

El nuevo estilo de lugar de trabajo que se muestra es una mala práctica , tiempos de vestigio o pre-OOP, según el Código de limpieza del tío Bob.

  

Los argumentos se interpretan de forma más natural como entradas a una función.

     

Cualquier cosa que te obligue a verificar la firma de la función es equivalente   a una doble toma. Es una ruptura cognitiva y debe evitarse. En el   Días antes de la programación orientada a objetos, a veces era necesario   tener argumentos de salida. Sin embargo, gran parte de la necesidad de argumentos de salida   desaparece en los idiomas OO

    
respondido por el Tulains Córdova 23.06.2014 - 17:55
14

Citando el famoso libro "Código limpio" de Robert C. Martin:

  

Deben evitarse los argumentos de salida

     

Las funciones deben tener un pequeño número de argumentos

El segundo patrón viola ambas reglas, particularmente el "argumento de salida". En este sentido es peor que el primer patrón.

    
respondido por el claasz 23.06.2014 - 14:03
14

El segundo idioma puede ser más rápido, porque la persona que llama puede reutilizar una variable en un bucle largo, en lugar de que cada iteración cree una nueva instancia.

Generalmente no lo usaría, pero por ejemplo. En la programación del juego tiene su lugar. Por ejemplo, mire Vector3f de JavaMonkey que permite pasar una instancia que debe modificarse y devuelto como resultado.

    
respondido por el user470365 23.06.2014 - 16:17
10

No creo que sean dos piezas de código equivalentes. En el primer caso, tienes que crear el otherObject . Puede modificar la instancia existente en el segundo. Ambos tienen sus usos. El olor a código preferiría uno sobre otro.

    
respondido por el Euphoric 23.06.2014 - 13:57
6

Realmente depende del idioma.

En Java, la segunda forma puede ser un anti-patrón, pero algunos lenguajes tratan el paso de parámetros de manera diferente. En Ada y VHDL, por ejemplo, en lugar de pasar por valor o por referencia, los parámetros pueden tener los modos in , out o in out .

Es un error modificar un parámetro in o leer un parámetro out , pero cualquier cambio en un parámetro in out se devuelve al interlocutor.

Por lo tanto, las dos formas en Ada (también son VHDL legales) son

function MyObject2OtherObject(mo : in MyObject) return OtherObject is
begin
    ... Do the conversion
    return otherObject;
end MyObject2OtherObject;

y

procedure MyObject2OtherObject(mo : in MyObject; oo : out OtherObject) is
begin
    ... Do the conversion
    oo := ... the conversion result;
end MyObject2OtherObject;

Ambos tienen sus usos; un procedimiento puede devolver múltiples valores en múltiples parámetros Out mientras que una función solo puede devolver un único resultado. Debido a que el propósito del segundo parámetro se establece claramente en la declaración del procedimiento, no puede haber objeción a este formulario. Tiendo a preferir la función por legibilidad. pero habrá casos en los que el procedimiento sea mejor, p. ej. donde el llamante ya ha creado el objeto.

    
respondido por el Brian Drummond 24.06.2014 - 00:11
3

De hecho, parece maloliente, y sin ver más contexto es imposible decirlo con seguridad. Podría haber dos razones para hacer esto, aunque hay alternativas para ambos.

Primero, es una forma concisa de implementar una conversión parcial o dejar el resultado con los valores predeterminados si la conversión falla. Es decir, podría tener esto:

public void ConvertFoo(Foo from, Foo to) {
    if (can't convert) {
        return;
    }
    ...
}

Foo a;
Foo b = DefaultFoo();
ConvertFoo(a, b);
// If conversion fails, b is unchanged

Por supuesto, generalmente esto se maneja usando excepciones. Sin embargo, incluso si es necesario evitar las excepciones por cualquier motivo, hay una mejor manera de hacerlo: TryParse patrón es una opción.

Otra razón es que podría ser por razones puramente de coherencia, por ejemplo, es parte de una API pública donde se utiliza este método para todas las funciones de conversión por cualquier razón (como otras funciones de conversión que tienen varias salidas).

Java no es bueno para manejar múltiples salidas, no puede tener parámetros de solo salida como algunos idiomas, o tener múltiples valores de retorno como otros, pero aún así, puede usar objetos de retorno.

La razón de la consistencia es bastante escasa, pero lamentablemente puede ser la más común.

  • Tal vez los policías de estilo en su lugar de trabajo (o su código base) provienen de un fondo que no es de Java y se han mostrado reacios a cambiar.
  • Su código puede haber sido un puerto de un idioma donde este estilo es más idiomático.
  • Es posible que su organización necesite mantener la consistencia de la API en diferentes idiomas, y este fue el estilo de denominador común más bajo (es absurdo, pero sucede incluso para Google ).
  • O tal vez el estilo tenía más sentido en el pasado lejano y se transformó en su forma actual (por ejemplo, podría haber sido el patrón TryParse pero algún predecesor bien intencionado eliminó el valor de retorno después de descubrir que nadie lo comprobó) .
respondido por el congusbongus 24.06.2014 - 05:45
2

La ventaja del segundo patrón es que obliga a la persona que llama a tomar posesión y responsabilidad por el objeto creado. No hay duda de si el método creó o no el objeto o lo obtuvo de un grupo reutilizable. La persona que llama sabe que es responsable de la vida útil y la eliminación del nuevo objeto.

Las desventajas de este método son:

  1. No se puede utilizar como un método de fábrica, la persona que llama debe conocer el subtipo exacto de OtherObject que necesita y construirlo por adelantado.
  2. No se puede usar con objetos que requieren parámetros en su constructor si esos parámetros provienen de MyObject . OtherObject debe ser construible sin saber acerca de MyObject .

La respuesta se basa en mi experiencia en c #, espero que la lógica se traduzca a Java.

    
respondido por el Rotem 23.06.2014 - 14:35
2

Dada la semántica suelta, myObjectToOtherObject también podría significar que mueves algunos datos del primer objeto al segundo o que lo conviertas completamente, el segundo método parece más adecuado.

Sin embargo, si el nombre del método fuera Convert (que debería ser si observamos la parte de "... hacer la conversión"), diría que el segundo método no tendría ningún sentido. No convierte un valor en otro valor que ya existe, IMO.

    
respondido por el guillaume31 23.06.2014 - 16:52

Lea otras preguntas en las etiquetas