2009-11-19 22 views
25

¿Cuándo se considera una mala práctica usar la palabra clave estática en Java en las firmas de métodos? Si un método realiza una función basada en algunos argumentos, y no requiere acceso a campos que no son estáticos, ¿no querría siempre que estos tipos de métodos fueran estáticos?¿Cuándo NO utilizar la palabra clave estática en Java?

Respuesta

30

Una razón por la que puede no querer que sea estática es permitir que se anule en una subclase. En otras palabras, el comportamiento puede no depender de los datos dentro del objeto, sino del tipo exacto del objeto. Por ejemplo, podría tener un tipo de colección general, con una propiedad isReadOnly que devolvería false en colecciones siempre mutables, true en colecciones siempre inmutables, y dependería de variables de instancia en otras.

Sin embargo, esto es bastante raro en mi experiencia, y generalmente debe especificarse explícitamente para mayor claridad. Normalmente haré un método que no dependa de ningún estado de objeto estático.

+1

@Downvoter: ¿Te importa explicar por qué? –

+12

Static no se trata de acceder a los campos de miembros o no. Se trata de semántica de clase. Si un método se aplica a las instancias de la clase, no debe ser estático. En su caso, es su instancia de colección que es de solo lectura, no la clase en sí misma, por lo que la función debe ser no estática. Static se trata realmente de métodos de clase, para fábricas o funciones de utilidad. –

+2

Por favor, déjenme el tiempo para realmente escribir mi comentario ;-) –

4

Lo que dices es cierto, pero ¿qué sucede cuando quieres anular el comportamiento de ese método en una clase derivada? Si es estático, no puedes hacer eso.

Como ejemplo, considere la siguiente clase de tipo DAO:

class CustomerDAO { 
    public void CreateCustomer(Connection dbConn, Customer c) { 
     // Some implementation, created a prepared statement, inserts the customer record. 
    } 

    public Customer GetCustomerByID(Connection dbConn, int customerId) { 
     // Implementation 
    } 
} 

Ahora, ninguno de estos métodos requieren ningún "estado". Todo lo que necesitan se pasa como parámetros. Entonces PODRÍAN fácilmente ser estáticos. Ahora el requisito viene que necesita dar soporte a una base de datos diferente (digamos Oracle)

Dado que estos métodos no son estáticos, sólo podría crear una nueva clase DAO:

class OracleCustomerDAO : CustomerDAO { 
    public void CreateCustomer(Connection dbConn, Customer c) { 
     // Oracle specific implementation here. 
    } 

    public Customer GetCustomerByID(Connection dbConn, int customerId) { 
     // Oracle specific implementation here. 
    } 
} 

Esta nueva clase podría ahora ser utilizado en lugar del anterior. Si está utilizando la inyección de dependencia, es posible que ni siquiera requiera un cambio de código.

Pero si hubiéramos hecho esos métodos estáticos, eso haría las cosas mucho más complicadas ya que no podemos simplemente anular los métodos estáticos en una nueva clase.

+0

+1, incluso los métodos sin estado pueden pertenecer a una instancia y estar disponibles para anular. – erickson

0

Así es. De hecho, debe contorsionar lo que de otra manera sería un diseño razonable (para tener algunas funciones no asociadas con una clase) en términos de Java. Es por eso que ves clases catch-all como FredsSwingUtils y YetAnotherIOUtils.

21

En general, prefiero los métodos de instancia por las siguientes razones:

  1. métodos estáticos que el análisis sea difícil porque no pueden ser reemplazados,
  2. métodos estáticos son más de procedimiento orientado.

En mi opinión, los métodos estáticos están bien para las clases de utilidad (como StringUtils) pero prefiero evitar su uso tanto como sea posible.

+2

+1 especialmente para la mención de prueba. Estamos usando JUnit, y los métodos de anulación en objetos simulados son un requisito. –

+12

En cuanto a 2: OO es una herramienta, no un objetivo. – erikkallen

+1

@erikkallen De acuerdo. Pero cuando uso un idioma OO, me gusta usar esta herramienta. –

0

cuando desea utilizar un miembro de clase independientemente de cualquier objeto de esa clase, debe declararse estático.
Si se declara estático, se puede acceder sin una instancia existente de un objeto de la clase. Un miembro estático es compartido por todos los objetos de esa clase específica.

40

Dos de los mayores males que se puedan encontrar en las aplicaciones Java a gran escala son

  • Los métodos estáticos, excepto aquellos que son funciones puras *
  • campos estáticos mutables

Estos ruina la modularidad, extensibilidad y capacidad de prueba de su código en un grado que me doy cuenta de que no puedo esperar convencerlo en este tiempo y espacio limitados.

* Una "función pura" es cualquier método que no modifica ningún estado y cuyo resultado no depende más que de los parámetros que se le proporcionan. Por lo tanto, por ejemplo, cualquier función que realice E/S (directa o indirectamente) no es una función pura, pero Math.sqrt(), por supuesto, sí lo es.

More blahblah about pure functions (autoenlace) y por qué quiere mantenerlos.

Lo invito encarecidamente a que favorezca el estilo de programación de "inyección de dependencia", posiblemente respaldado por un marco como Spring o Guice (descargo de responsabilidad: soy coautor de este último). Si hace esto bien, esencialmente nunca necesita estado estático mutable o métodos estáticos no puros.

+2

Así que argumentaría en contra de hacer cualquier E/S dentro de un método estático, incluso si no hace nada con el estado del objeto, es una clase sellada, y está pasando el objeto en el que realizar el IO como argumento ? Estoy de acuerdo en que todavía no será puro, pero no veo cómo hacer que sea un método de instancia ayuda en este caso. –

+1

(Estoy de acuerdo con que los campos estáticos mutables generalmente sean una mala idea, claro). –

+4

En una nota lateral, para todos los demás: expresar desacuerdo con Kevin es como expresar desacuerdo con Eric Lippert. Me siento nerviosa, casi esperando que me golpeen en la cabeza con un gran reclamo. Por favor, se amable, Kevin ... –

0

Una molestia adicional sobre los métodos estáticos: no hay una manera fácil de pasar una referencia a dicha función sin crear una clase contenedora alrededor de ella. P.ej. - algo así como:

FunctorInterface f = new FunctorInterface() { public int calc(int x) { return MyClass.calc(x); } }; 

Odio este tipo de trabajo de java. ¿Tal vez una versión posterior de java obtendrá delegados o un mecanismo similar de puntero de función/tipo de procedimiento?

Una pequeña queja, pero una cosa más para no como sobre funciones estáticas gratuitas, er, métodos.

1

Los métodos estáticos generalmente se escriben con dos propósitos. El primer propósito es tener algún tipo de método de utilidad global, similar al tipo de funcionalidad que se encuentra en java.util.Collections. Estos métodos estáticos son generalmente inofensivos. El segundo objetivo es controlar la instanciación de objetos y limitar el acceso a los recursos (como las conexiones de bases de datos) a través de varios patrones de diseño, como singletons y factories. Estos pueden, si se implementan mal, generar problemas.

Para mí, hay dos inconvenientes a la utilización de métodos estáticos:

  1. Ellos hacen menos código modular y más difícil de probar/extensión. La mayoría de las respuestas ya abordaron esto, así que no entraré en eso más.
  2. Los métodos estáticos tienden a dar lugar a algún tipo de estado global, que a menudo es la causa de errores insidiosos. Esto puede ocurrir en un código mal escrito que está escrito para el segundo propósito descrito anteriormente. Déjame elaborar.

Por ejemplo, considere un proyecto que requiere registrar ciertos eventos en una base de datos, y también depende de la conexión de la base de datos para otro estado. Supongamos que normalmente, la conexión de la base de datos se inicializa primero, y luego el marco de trabajo de registro se configura para escribir ciertos eventos de registro en la base de datos. Ahora suponga que los desarrolladores deciden pasar de un marco de base de datos escrito a mano a un marco de base de datos existente, como hibernación.

Sin embargo, es probable que este marco tenga su propia configuración de registro, y si utiliza el mismo marco de trabajo de registro que el suyo, entonces existe una buena posibilidad de que haya varios conflictos entre las configuraciones. De repente, cambiar a un marco de base de datos diferente produce errores y fallas en diferentes partes del sistema que aparentemente no están relacionadas. El motivo por el cual pueden ocurrir estas fallas es porque la configuración de registro mantiene el estado global al que se accede a través de métodos y variables estáticos, y varias partes del sistema pueden anular varias propiedades de configuración.

Para evitar estos problemas, los desarrolladores deben evitar almacenar cualquier estado a través de métodos estáticos y variables. En su lugar, deben construir API limpias que permitan a los usuarios administrar y aislar el estado según sea necesario. BerkeleyDB es un buen ejemplo aquí, encapsulando el estado a través de un objeto Environment en lugar de a través de llamadas estáticas.

+0

Este es un argumento muy coherente contra el estado estático, pero no contra los métodos estáticos en general. La mayoría de los métodos estáticos que escribo solo usan sus parámetros. Es cierto que suelo usar variables del registrador estático, lo que acepto tiene problemas ... –

+0

Correcto, eso es lo que traté de delinear en el primer párrafo: los métodos estáticos que no alteran ningún estado fuera de sus parámetros generalmente están bien, pero los métodos estáticos que manejan el estado pueden ser problemáticos. Así que supongo que como regla general para decidir cuándo escribir un método estático, debería ver si algún estado se verá afectado por el método. – toluju

0

Dos preguntas aquí 1) ¿Un método estático que crea objetos permanece cargado en la memoria cuando se accede por primera vez? ¿No es esto (quedando cargado en la memoria) un inconveniente? 2) Una de las ventajas de usar Java es su característica de recolección de basura. ¿No ignoramos esto cuando utilizamos métodos estáticos?

Cuestiones relacionadas