¿Hacer métodos que no dependen de campos de instancia, estáticos?

19

Recientemente comencé a programar en Groovy para un marco de prueba de integración, para un proyecto Java. Uso Intellij IDEA con el complemento Groovy y me sorprende ver una advertencia para todos los métodos que no son estáticos y no dependen de ningún campo de instancia. En Java, sin embargo, esto no es un problema (al menos desde el punto de vista de IDE).

¿Deberían todos los métodos que no dependen de ningún campo de instancia transformarse en funciones estáticas? Si es cierto, ¿es esto específico de Groovy o está disponible para OOP en general? ¿Y por qué?

m3th0dman
fuente
¿Estos métodos llaman a otros métodos de instancia? ¿O literalmente no tienen nada que ver con un objeto de esa clase? ¿Puede dar un ejemplo?
Ray Toal

Respuestas:

26

Tenga en cuenta que IDEA también tiene esta inspección para Java, se llama Método puede ser 'estático' ,

Esta inspección informa sobre cualquier método que pueda hacerse estático de forma segura. Un método puede ser estático si no hace referencia a ninguno de los métodos no estáticos y campos no estáticos de su clase y no se anula en una subclase ...

Sin embargo, para el código Java, esta inspección está desactivada de forma predeterminada (el programador puede activarla a su discreción). La razón de esto es muy probable que la validez / utilidad de dicha inspección pueda ser cuestionada, en base a un par de fuentes bastante autorizadas.

Para empezar, el tutorial oficial de Java es bastante restrictivo sobre cuándo los métodos deben ser estáticos:

Un uso común de los métodos estáticos es acceder a los campos estáticos.

Dado lo anterior, se podría argumentar que activar la inspección mencionada por defecto no cumple con el uso recomendado del modificador estático en Java.

Además, hay un par de otras fuentes que van tan lejos como para sugerir un enfoque juicioso sobre el uso de ideas que se encuentran detrás de esta inspección o incluso desalentarla.

Consulte, por ejemplo, el artículo de Java World: Mr. Happy Object enseña métodos estáticos :

Cualquier método que sea independiente del estado de la instancia es candidato para ser declarado como estático.

Tenga en cuenta que digo "candidato para ser declarado como estático". Incluso en el ejemplo anterior, nada te obliga a declarar instances()como estático. Declararlo como estático solo hace que sea más conveniente llamar, ya que no necesita una instancia para llamar al método. A veces tendrá métodos que no parecen depender del estado de la instancia. Es posible que no desee que estos métodos sean estáticos. De hecho, probablemente solo desee declararlos como estáticos si necesita acceder a ellos sin una instancia.

Además, aunque puede declarar un método como estático, es posible que no desee hacerlo debido a los problemas de herencia que interfiere en su diseño. Eche un vistazo al "Diseño eficaz orientado a objetos" para ver algunos de los problemas que enfrentará ...

Un artículo en el blog de pruebas de Google llega incluso a afirmar que los métodos estáticos son muerte a la testabilidad :

Hagamos un ejercicio mental. Supongamos que su aplicación no tiene más que métodos estáticos. (Sí, un código como ese es posible escribir, se llama programación de procedimientos). Ahora imagine el gráfico de llamadas de esa aplicación. Si intenta ejecutar un método de hoja, no tendrá problemas para configurar su estado y afirmar todos los casos de esquina. La razón es que un método de hoja no hace más llamadas. A medida que se aleje de las hojas y se acerque al main()método de la raíz , será cada vez más difícil establecer el estado en su prueba y será más difícil afirmar las cosas. Muchas cosas serán imposibles de afirmar. Sus pruebas se harán progresivamente más grandes. Una vez que alcanzas elmain()método ya no tiene una prueba de unidad (ya que su unidad es la aplicación completa) ahora tiene una prueba de escenario. Imagine que la aplicación que está intentando probar es un procesador de textos. No hay mucho que puedas afirmar del método principal ...

A veces, los métodos estáticos son una fábrica para otros objetos. Esto exubera aún más el problema de prueba. En las pruebas confiamos en el hecho de que podemos conectar objetos de manera diferente reemplazando dependencias importantes con simulacros. Una vez newque se llama a un operador, no podemos anular el método con una subclase. Una persona que llama de tal fábrica estática está permanentemente vinculada a las clases concretas que produjo el método de fábrica estática. En otras palabras, el daño del método estático está mucho más allá del método estático en sí. Unir el cableado del gráfico de objetos y el código de construcción en un método estático es muy malo, ya que el cableado del gráfico de objetos es cómo aislamos las cosas para las pruebas ...


Verá, dado lo anterior, parece natural que la inspección mencionada esté desactivada por defecto para Java.

Desarrolladores IDE tendrían una muy difícil explicar por qué creen que es tan importante como para ponerlo de manera predeterminada, en contra de las recomendaciones ampliamente reconocidos y las mejores prácticas.

Para Groovy, las cosas son bastante diferentes. Ninguno de los argumentos enumerados anteriormente se aplica, particularmente el que se refiere a la capacidad de prueba , como se explica, por ejemplo, en el artículo Métodos estáticos burlones en Groovy en Javalobby:

Si la clase Groovy que está probando hace que las llamadas sean un método estático en otra clase Groovy, entonces podría usar ExpandoMetaClass que le permite agregar dinámicamente métodos, constructores, propiedades y métodos estáticos ...

Esta diferencia es probable por qué la configuración predeterminada para la inspección mencionada es opuesta en Groovy. Mientras que en Java el valor predeterminado "activado" sería fuente de confusión de los usuarios, en Groovy, una configuración opuesta podría confundir a los usuarios de IDE.

"Oye, el método no usa campos de instancia, ¿por qué no me lo advirtió?" Esa pregunta sería fácil de responder para Java (como se explicó anteriormente), pero para Groovy, simplemente no hay una explicación convincente.

mosquito
fuente
Por cierto, ReSharper (hecho por JetBrains para C # / Visual Studio) sugiere lo mismo
Konrad Morawski el
66
Hay una distinción importante entre los métodos estáticos con y sin efectos secundarios. El extracto de Google realmente aborda el primero.
Assylias 01 de
@assylias Sí, pero también analiza cómo los métodos de fábrica pueden dificultar las pruebas (ya que acoplan estrechamente las dependencias en la aplicación). El uso de un marco de inyección de dependencias es una de las mejores soluciones para esto, y también resuelve muchos otros problemas.
Según Lundberg el
5

Es difícil imaginar que esto tenga un efecto perceptible en el rendimiento. El único beneficio que puedo ver al hacerlos statices que proporciona una indicación visual de que el estado de la instancia no se ve afectado. En otras palabras, le dice a la persona que lee el código fuente algo ... "interesante" sobre ese método, simplemente en virtud de que esté allí. La verdadera pregunta es, ¿aclara o confunde? "¿Por qué es estático este método? ¿Es un método de fábrica? ¿Es necesaria la capacidad de llamarlo sin una instancia de objeto?"

Además, a algunas personas no les gustan los métodos estáticos, porque afirman que no se pueden burlar de ellos y, por lo tanto, no son comprobables, o algo por el estilo. Ciertamente, si lo está haciendo estático por alguna de las razones habituales, como proporcionar un método de fábrica, por ejemplo, entonces estoy a favor. No estoy seguro de que hacer que los métodos sean estáticos solo porque no tocan el estado de instancia es un mandato.

Robert Harvey
fuente
55
Tenga en cuenta que (dentro de Java) un método estático no se puede anular. Si bien no suele ser un problema, significa que algunas subclases más tarde no pueden cambiar esa implementación. Esto no quiere decir que un método estático no sea la respuesta correcta, sino parte de las consideraciones de diseño.
2
@ user40980 vale la pena considerarlo, es cierto, pero también vale la pena considerar que la herencia puede ser una herramienta torpe que a menudo se usa incorrectamente, y varias figuras prominentes argumentan que todas las clases deberían ser finalo específicamente diseñadas teniendo en cuenta la herencia.
sara
3

Creo que es posible para permitir la refactorización para ser visto .

Una vez que el método se ha vuelto estático, está claro que se puede sacar de la clase, por ejemplo, a una clase de unidad.

También es fácil transformarlo en un método de instancia de uno de sus parámetros, a menudo aquí es donde debería estar el código.

Ian
fuente
-1

Tenga en cuenta que puede tener clases sin estado que implementan alguna interfaz (por ejemplo java.lang.Runnable, no puede hacer que sus métodos sean estáticos. Algunos patrones (por ejemplo, Estrategia) también pueden producir objetos sin estado que incluso pueden tener varios métodos.

Los estáticos son primos hermanos de los solteros. Será muy difícil pasar de lo estático a lo no estático en un momento posterior, por lo que cuando necesite agregar un estado, tendrá la tentación de comenzar a introducir variables estáticas.

Eugene
fuente
¿Cómo responde esto a la pregunta que se hace?
mosquito
1
¿Por qué es difícil pasar de un estado a otro? Yo diría que es al revés. Es más fácil contaminar algo puro que purificar algo contaminado.
sara