¿Es una "práctica estática" una buena práctica?

13

Recientemente, he notado que hay una opción para tener métodos estáticos en las interfaces. Igual que con los campos estáticos de la interfaz, hay un comportamiento interesante: estos no se heredan.

No estoy seguro de que sea útil en las interfaces reales que se van a implementar. Sin embargo, le permite al programador crear interfaces que solo son envolventes para cosas estáticas, como por ejemplo, Las clases de utilidad son.

Un ejemplo simple es solo un sobre para constantes globales. Comparado con una clase, puede notar fácilmente el texto faltante de public static final como se suponen (haciéndolo menos detallado).

public interface Constants {
    String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
    int DEFAULT_TIMEOUT_MS = 30;
}

También podrías hacer algo más complejo, como este pseudo-enum de claves de configuración.

public interface ConfigKeys {
    static createValues(ConfigKey<?>... values) {
        return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
    }

    static ConfigKey<T> key(Class<T> clazz) {
        return new ConfigKey<>(clazz);
    }

    class ConfigKey<T> {
        private final Class<T> type;
        private ConfigKey(Class<T> type) {
            this.type = type;
        }
        private Class<T> getType() {
            return type;
        }
    }
}

import static ConfigKeys.*;
public interface MyAppConfigKeys {
    ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
    ConfigKey<String> COMPANY_NAME = key(String.class);

    Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);

    static values() {
        return VALUES;
    }
}

También podría crear alguna "clase" de utilidad de esta manera. Sin embargo, en los servicios públicos, a menudo es útil utilizar métodos de ayuda privados o protegidos, lo que no es posible en las clases.

Considero que es una buena característica nueva, y especialmente el hecho de que los miembros estáticos no se heredan es un concepto interesante que se introdujo solo en las interfaces.

Me pregunto si puede considerarlo una buena práctica. Si bien el estilo del código y las mejores prácticas no son axiomáticos y hay espacio para la opinión, creo que generalmente existen razones válidas que respaldan la opinión.

Me interesan más las razones (no) para usar patrones como estos dos.

Tenga en cuenta que no pretendo implementar esas interfaces. Son simplemente un sobre por su contenido estático. Solo pretendo usar las constantes o los métodos y posiblemente usar la importación estática.

    
pregunta Vlasec 16.12.2016 - 03:00

5 respuestas

1
  

Un ejemplo simple es solo un sobre para constantes globales.

Poner constantes en las interfaces se llama Constant Interface Antipattern ya que las constantes son a menudo simplemente un detalle de implementación. Otros inconvenientes se resumen en el artículo de Wikipedia en la Interfaz constante .

  

También puedes crear una "clase" de utilidad de esta manera.

De hecho, el documento Java indica que los métodos estáticos pueden hacer que sea más fácil organice los métodos de ayuda, por ejemplo, al llamar a métodos de ayuda desde los métodos predeterminados.

    
respondido por el Markus Pscheidt 16.12.2016 - 11:11
1

Como se indica en la pregunta, la interfaz no está diseñada para ser implementada (o instanciada). Entonces podríamos compararlo con una clase que tiene un constructor privado:

  • La clase no se puede extender sin super() a la llamada, pero la interfaz se puede "implementar"
  • No se puede crear una instancia de la clase sin reflexiones, mientras que la interfaz se puede crear fácilmente como una clase anónima tan simple como esta: new MyInterface() {};

Esta comparación es a favor de la clase, ya que permite un mayor control. Dicho esto, la clase tampoco tiene la intención de ser portadora de cosas estáticas, es de esperar que tenga instancias. Bueno, no hay una opción perfecta.

También hay algo extraño acerca de la herencia de la "interfaz estática":

  • Una clase de "implementación" hereda los campos, pero no hereda los métodos estáticos
  • Una interfaz que se extiende no hereda ningún miembro estático
  • (Si bien una clase que extiende una clase hereda a todos los miembros no privados ... y dado que no puede extenderse por una interfaz, hay menos espacio para la confusión)

Estas podrían ser razones para considerarlo como un mal patrón y seguir utilizando clases estáticas para estos casos. Sin embargo, para alguien adicto al azúcar sintáctico puede ser tentador incluso con las desventajas.

    
respondido por el Vlasec 16.12.2016 - 16:29
0

Como @MarkusPscheidt esta idea es esencialmente una extensión de la interfaz constante . Este enfoque inicialmente se usó ampliamente para permitir que un solo conjunto de constantes sea heredado por muchas clases dispares. La razón por la que esto terminó siendo considerado un antipattern fue debido a los problemas que se encontraron al usar este enfoque en proyectos reales. No veo ninguna razón para pensar que estos problemas solo se relacionarían con las constantes.

Probablemente lo más importante es que realmente no hay necesidad de hacer esto. Utilice importaciones estáticas y sea explícito sobre lo que está importando y desde dónde.

    
respondido por el JimmyJames 16.12.2016 - 19:56
0

Yo diría que, si está interesado en cómo usar la nueva función correctamente, eche un vistazo al código en el JDK. Los métodos predeterminados en las interfaces son muy utilizados y fáciles de encontrar, pero los métodos estáticos en las interfaces parecen ser muy poco frecuentes. Algunos ejemplos incluyen java.time.chrono.Chronology , java.util.Comparator , java.util.Map y bastantes interfaces en java.util.function y java.util.stream .

La mayoría de los ejemplos que analicé implican el uso de aquellas API que probablemente sean muy comunes: conversión entre diferentes tipos en la API de tiempo, por ejemplo, para comparaciones que probablemente se realicen con frecuencia entre objetos pasados a funciones o Objetos contenidos en colecciones. Mi conclusión: si hay una parte de su API que necesita ser flexible, pero puede cubrir, por ejemplo, el 80% de los casos de uso con algunos valores predeterminados, considere el uso de métodos estáticos en sus interfaces. Dada la poca frecuencia con la que esta función parece ser utilizada en el JDK, sería muy conservador al utilizarla en mi propio código.

Sus ejemplos no se parecen en nada a lo que veo en el JDK. Para esos casos específicos, es casi seguro que debería crear un enum que implemente la interfaz deseada. Una interfaz describe un conjunto de comportamientos y realmente no tiene ningún negocio manteniendo una colección de sus implementaciones.

    
respondido por el ngreen 16.12.2016 - 19:59
-1
  

Me pregunto si hay razones para no usarlo.

¿Qué hay de, um, la compatibilidad con JVM más antiguas?

  

¿Considera que esta es una buena idea en general?

No. Es un cambio incompatible con versiones anteriores que agrega cero a la expresividad del lenguaje. Dos pulgares hacia abajo.

  

¿Hay algunas situaciones modelo en las que recomiendas clases?

Recomiendo encarecidamente usar clases para contener los detalles de la implementación. Una interfaz solo significa "este objeto admite operaciones XYZ" y eso no tiene nada que ver con ningún método estático que pueda pensar en incluir en la declaración de la interfaz. Esta característica es como un sillón reclinable con un mini refrigerador incorporado. Claro que tiene algunos usos específicos, pero no tiene el peso suficiente para merecer estar en la corriente principal.

ACTUALIZACIÓN: Por favor, no más votos a la baja. Claramente, algunas personas piensan que los métodos estáticos en las interfaces son las rodillas de la abeja, y por este medio estoy capitulando. Simplemente eliminaría esta respuesta, pero los comentarios adjuntos son una discusión interesante.

    
respondido por el DepressedDaniel 16.12.2016 - 03:24

Lea otras preguntas en las etiquetas