Campos vs argumentos del método [cerrado]

9

Acabo de comenzar a escribir una nueva clase y se me ocurrió que estaba agregando muchos argumentos de métodos que no son estrictamente necesarios. Esto sigue un hábito para evitar tener un estado en las clases que es específico para alguna llamada de método, en lugar de ser una configuración general o dependencias de la clase.

Hacerlo significa que muchos métodos que no pueden tener argumentos terminan en uno, dos o tres.

Me gustaría escuchar sus opiniones sobre lo que piensa de esta compensación, y cómo decide qué enfoque adoptar en cada situación.

Dado que el código es a menudo más fácil de entender que el inglés al describir el código, creé una pequeña esencia que tiene ambas variantes: https://gist.github.com/JeroenDeDauw/6525656

Jeroen De Dauw
fuente
Los argumentos que se usan solo como una variable local (no global para la vida útil del objeto) solo deben estar dentro del alcance siempre que tenga sentido ... Me resulta muy irritante cuando los desarrolladores almacenan el estado de no instancia como estado de instancia porque es conveniente ... Solo mi opinión. Hace que sea difícil ver cómo es realmente el flujo de ejecución.
Max
El uso de parámetros y dejar que la clase se encargue de si debe cambiar o no el estado mientras se ejecuta un método, se vincula muy bien con el principio de "decir no preguntar" . Solo tenga en cuenta que decir no preguntar no significa que no pueda consultar un objeto sobre su estado ( obvio )
Marjan Venema

Respuestas:

2

Dado que el único método externo visible de su ejemplo es updateTable, creo que está bien usar campos en lugar de parámetros de método.

Si esto es parte de una clase más genérica (por ejemplo TableTools), movería los métodos auxiliares que necesitan el estado a una clase interna oculta.

Ejemplo de pseudocódigo:

class TableTools {
    ...
    public void updateTable(currentTable, newTable) {
        TableUpdater u = new TableUpdater(schemaModifier, currentTable, newTable);
        u.removeRemovedFields();
        u.addAddedFields();
     }

     private class TableUpdater { ... }
}

De esta forma, evita los campos que se utilizan solo con un método público. Además, el código es seguro para subprocesos en el sentido de que cada llamada a updateTable usa su propia copia de TableUpdater y, por lo tanto, de las variables de instancia de TableUpdater.

Heinzi
fuente
7

El uso de campos coopta la capacidad de tener subprocesos múltiples disponibles para los métodos que usan esos campos.

Usar campos como este es solo un poco mejor que usar globales desde un punto de vista de reutilización y mantenibilidad, el punto clave aquí es que las configuraciones complejas necesitan documentación cuidadosa y actualizada sobre qué métodos usan y / o controlan qué campos; algo que no necesita hacer cuando usa argumentos.

monstruo de trinquete
fuente
Multhithreading no es relevante para mi caso de uso, como lo es en PHP. Estoy de acuerdo en que este enfoque es malo si la forma en que se usan los campos no es trivial. En este caso, solo se escriben (y siempre se escriben) desde el único método público. No preveo que esto cause problemas. En cuanto a que los campos como este solo son un poco mejores que los globales, no estoy seguro de lo que quieres decir. ¿Puedes elaborar?
Jeroen De Dauw
7

En palabras simples:

  • los métodos deben tener la menor cantidad de argumentos posible (Martin's Clean Code)
  • Una de las características de los objetos es que pueden (y deberían) tener un estado
  • Los métodos no estáticos que no funcionan en el estado del objeto, es decir, reciben todo como parámetros, no son cohesivos
  • los métodos no cohesivos también podrían hacerse estáticos y agruparse en una clase de utilidad

Nuevamente, en mi humilde opinión, los métodos no cohesivos pertenecen a una clase de utilidad y no a una clase con un nombre de dominio.

Tulains Córdova
fuente
1

¡No uses campos en el caso actual! Dos "hilos" que usan el objeto al mismo tiempo se confundirán seriamente. No tienen que ser reales, hilos separados tampoco (de ahí las citas). Si configura el objeto para una tabla, luego llame a un método que lo usa para otra tabla, luego intente usar la configuración original, tiene un problema. Quédese con los parámetros por el momento.

Lo que quiere hacer aquí es crear una nueva clase de actualización que se use en un solo caso. La clase original podría tener un método para crear una instancia cuando sea necesario. La nueva clase tendría campos. Tienes lo mejor de ambos mundos. A veces es más simple seguir los parámetros, pero en su ejemplo ya está llegando a donde una clase separada sería mejor.

RalphChapin
fuente
0

Creo que la elección debe estar de acuerdo con la situación real, tal como la ves. Si un elemento pertenece a una instancia, debe verse como su campo. Si el elemento es externo a la instancia, debe pasarse como un parámetro de método.

Deberíamos guiarnos en este caso no por la efectividad (la diferencia es insignificante de todos modos), o (¡Dios salve!) La facilidad de escribir, sino por la comprensibilidad y la naturalidad del código.

Gangnus
fuente
0

En mi opinión, si está escribiendo código que hace algo a algo, entonces debe tomar parámetros que definan a qué cosas debe hacerles y su nombre debe definir lo más posible lo que le hace.

Si está escribiendo código que empaqueta una acción para que se realice en algo, entonces debe envolver las cosas que se deben realizar en un objeto y pasarlas a lo que hace algo .

Esta acción se convierte en una especie de metadescripción de las llamadas a los métodos de la primera que luego puede realizar en una fecha posterior haciendo cola o incluso decide no hacerlo por alguna razón.

Entonces su pregunta se traduce en ¿ es una Acción o una Función ? Una Acción puede posponerse o cancelarse y, por lo tanto, debe encapsular aquello sobre lo que actúa. Una función ocurre inmediatamente, por lo que no es necesario preservar sus parámetros.

Puede deshacer y Acción, pero no una Función .

OldCurmudgeon
fuente