Java: ¿es una mala idea tener clases completamente estáticas?

14

Estoy trabajando en un proyecto en solitario más grande y ahora mismo, y tengo varias clases en las que no veo ninguna razón para crear una instancia de.

Mi clase de dados en este momento, por ejemplo, almacena todos sus datos de forma estática y todos sus métodos también son estáticos. No necesito inicializarlo porque cuando quiero tirar los dados y obtener un nuevo valor, solo uso Dice.roll() .

Tengo varias clases similares que solo tienen una función principal como esta y estoy a punto de comenzar a trabajar en una clase de "controlador" que estará a cargo de todos los eventos (como cuando un jugador se mueve, y qué turno actual es) y he encontrado que podría seguir la misma idea para esta clase. Nunca planeo crear múltiples objetos para estas clases específicas, ¿sería una mala idea hacerlos completamente estáticos?

Me preguntaba si esto se considera una "mala práctica" cuando se trata de Java. Por lo que he visto, la comunidad parece estar dividida en este tema. De todos modos, me encantaría hablar sobre esto y los enlaces a los recursos también serían excelentes.

    
pregunta HexTeke 11.04.2018 - 08:10

4 respuestas

19

No hay nada malo con las clases estáticas que son realmente estáticas . Es decir, no hay un estado interno del que hablar, lo que causaría un cambio en la salida de los métodos.

Si Dice.roll() simplemente devuelve un nuevo número aleatorio de 1 a 6, no está cambiando de estado. Por supuesto, puede que esté compartiendo una instancia de Random , pero no consideraría que un cambio de estado como, por definición, la salida siempre será buena, aleatoria. También es seguro para subprocesos, por lo que no hay problemas aquí.

A menudo verá "Ayudante" final u otras clases de utilidad que tienen un constructor privado y miembros estáticos. El constructor privado no contiene lógica y sirve solo para evitar que alguien cree una instancia de la clase. El modificador final solo trae esta idea a casa que esta no es una clase de la que nunca querría derivar. Es meramente una clase de utilidad. Si se hace correctamente, no debe haber singleton u otros miembros de la clase que no sean en sí mismos estáticos y finales.

Mientras sigas estas pautas y no hagas singletons, no hay absolutamente nada de malo en esto. Menciona una clase de controlador, y esto casi sin duda requerirá cambios de estado, por lo que aconsejaría no usar solo métodos estáticos. Puede confiar mucho en una clase de utilidad estática, pero no puede hacer una clase de utilidad estática.

¿Qué se considera un cambio de estado para una clase? Bueno, excluyamos los números aleatorios por un segundo, ya que no son deterministas por definición y, por lo tanto, el valor de retorno cambia a menudo.

Una función pura es aquella que es determinista, es decir, para una entrada determinada, obtendrá una y exactamente una salida. Quieres que los métodos estáticos sean puras funciones. En Java hay formas de ajustar el comportamiento de los métodos estáticos para mantener el estado, pero casi nunca son buenas ideas. Cuando declara un método como static , el programador típico asumirá de inmediato que es una función pura. Desviarse del comportamiento esperado es cómo tiende a crear errores en su programa, generalmente hablando y debe evitarse.

Un singleton es una clase que contiene métodos estáticos como opuestos a "función pura" como puedes ser. Un único miembro privado estático se mantiene internamente en la clase que se utiliza para garantizar que exista exactamente una instancia. Esta no es la mejor práctica y puede causarle problemas más adelante por varias razones. Para saber de qué estamos hablando, aquí hay un ejemplo simple de un singleton:

// DON'T DO THIS!
class Singleton {
  private String name; 
  private static Singleton instance = null;

  private Singleton(String name) {
    this.name = name;
  }

  public static Singleton getInstance() {
    if(instance == null) {
      instance = new Singleton("George");
    }
    return instance;
  }

  public getName() {
    return name;
  }
}

assert Singleton.getInstance().getName() == "George"
    
respondido por el Neil 11.04.2018 - 08:30
9

Para dar un ejemplo de las limitaciones de una clase static , ¿qué pasa si algunos de tus jugadores quieren obtener una pequeña bonificación en sus tiradas? ¡Y están dispuestos a pagar mucho dinero! :-)

Sí, podría agregar otro parámetro, por lo que Dice.roll(bonus) ,

Más tarde necesitas D20s.

Dice.roll(bonus, sides)

Sí, pero algunos jugadores tienen la hazaña "supremamente capaz", por lo que nunca pueden "torear" (tirar un 1).

Dice.roll(bonus, sides, isFumbleAllowed) .

Esto se está complicando, ¿no es así?

    
respondido por el user949300 11.04.2018 - 16:33
3

En el caso particular de una clase de dados, creo que usar métodos de instancia en lugar de estáticos hará que las pruebas sean mucho más fáciles.

Si desea realizar una prueba unitaria de algo que usa una instancia de Dice (por ejemplo, una clase de Juego), desde sus pruebas puede inyectar alguna forma de prueba de doble de Dice que siempre devuelve una secuencia fija de valores. Tu prueba puede verificar que el juego tenga el resultado correcto para esas tiradas de dados.

No soy un desarrollador de Java, pero creo que sería mucho más difícil hacerlo con una clase de Dice completamente estática. Consulte enlace

    
respondido por el bdsl 11.04.2018 - 22:01
0

En realidad, esto se conoce como el patrón de Monostato , donde cada instancia (e incluso un "no-instancia") comparte su estado. Cada miembro es un miembro de la clase (es decir, no hay miembros de instancia). Se usan comúnmente para implementar clases de "herramientas" que agrupan un conjunto de métodos y constantes relacionados con una sola responsabilidad o requisito, pero no necesitan un estado para funcionar (son puramente funcionales). De hecho, Java viene con algunos de ellos incluidos (por ejemplo, Math ).

Un poco fuera de tema: rara vez estoy de acuerdo con el nombre de las palabras clave en VisualBasic, pero en este caso, creo que shared es claramente más claro y semánticamente mejor (está compartido entre la clase en sí y en todas sus instancias) que static (permanece después del ciclo de vida del ámbito en que se declaró).

    
respondido por el Jesus Alonso Abad 11.04.2018 - 20:54

Lea otras preguntas en las etiquetas