¿Cuál es el uso de las constantes de interfaz?

123

Estoy aprendiendo Java y acabo de descubrir que la interfaz puede tener campos, que son estáticos públicos y finales. No he visto ningún ejemplo de estos hasta ahora. ¿Cuáles son algunos de los casos de uso de estas constantes de interfaz? ¿Puedo ver algunos en la biblioteca estándar de Java?

unj2
fuente

Respuestas:

190

Poner miembros estáticos en una interfaz (e implementar esa interfaz) es una mala práctica e incluso hay un nombre para ello, el Antipattern de Interfaz Constante , vea Java efectivo , artículo 17:

El patrón de interfaz constante es un mal uso de las interfaces . Que una clase use algunas constantes internamente es un detalle de implementación. La implementación de una interfaz constante hace que este detalle de implementación se filtre en la API exportada de la clase. No tiene importancia para los usuarios de una clase que la clase implemente una interfaz constante. De hecho, incluso puede confundirlos. Peor aún, representa un compromiso: si en una versión futura se modifica la clase para que ya no necesite usar las constantes, aún debe implementar la interfaz para asegurar la compatibilidad binaria. Si una clase no final implementa una interfaz constante, todas sus subclases tendrán sus espacios de nombres contaminados por las constantes en la interfaz.

Hay varias interfaces constantes en las bibliotecas de la plataforma java, como java.io.ObjectStreamConstants. Estas interfaces deben considerarse anomalías y no deben emularse.

Para evitar algunos errores de la interfaz constante (porque no puede evitar que las personas la implementen), se debe preferir una clase adecuada con un constructor privado (ejemplo tomado de Wikipedia ):

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

Y para acceder a las constantes sin tener que calificarlas completamente (es decir, sin tener que prefijarlas con el nombre de la clase), use una importación estática (desde Java 5):

import static Constants.PLANCK_CONSTANT;
import static Constants.PI;

public class Calculations {

    public double getReducedPlanckConstant() {
        return PLANCK_CONSTANT / (2 * PI);
    }
}
Pascal Thivent
fuente
12
Bien, pero ¿qué pasa si tienes una interfaz que no es solo para una definición constante? Así que tengo una interfaz que es implementada por muchas clases, contiene declaraciones de métodos, pero también quiero agregar algunos valores comunes como el tamaño, por ejemplo. ¿Es realmente un mal patrón en este caso? En general, estoy de acuerdo en que crear interfaces solo para constantes es un antipatrón.
Łukasz Rzeszotarski
11
No es malo solo porque alguien lo diga en un libro. Siempre que no implemente esa interfaz para obtener acceso a esas constantes, está bien.
ACV
11
No No No. ¡Esa cita de Effective Java trata sobre otra cosa! La creación de interfaces solo constantes es una mejor alternativa a las clases que contienen esas constantes. El java efectivo dice: "Que una clase use algunas constantes internamente es un detalle de implementación". Pero aquí no es el caso. Estamos hablando de constantes 'globales'. ¿Y quién querría implementar una interfaz sin declaraciones de método en ella?
ACV
6
Estoy de acuerdo con ACV. Si la interfaz constante no es parte del módulo API exportado o cuando no está implementado en ninguna parte, no veo el problema. El uso de clases finales const es feo: necesita un constructor privado que satura el código porque no tiene ningún uso.
Lawrence
2
Esta respuesta no presenta el punto principal del libro "Eficaz Java" correctamente, porque "degrada" el punto principal poniéndolo entre corchetes: "(e implementando esa interfaz)". En cambio, enfatiza el punto de las constantes en las interfaces (que están bien a menos que implemente tal interfaz). En general, no es una mala respuesta, porque si lees detenidamente el fragmento citado, puedes ver lo que se había querido decir originalmente con el autor de "Effective Java". Pero lo encuentro engañoso. En mi opinión, la parte "y la implementación de esa interfaz" debe estar en negrita para enfatizarla.
krm
17

" El patrón de interfaz constante es un mal uso de las interfaces "

Quien elaboró ​​esta hipótesis, por muy gurú que sea, la inventó sobre la base de la necesidad de seguir implementando los malos hábitos y prácticas de manera eficiente. La hipótesis se basa en la promoción de la validez de malos hábitos de diseño de software.

Escribí una respuesta para refutar esa hipótesis aquí: ¿Cuál es la mejor manera de implementar constantes en Java? explicando la falta de fundamento de esta hipótesis.

Durante 10 años esa pregunta había permanecido abierta, hasta que se cerró dentro de 2 horas después de que publiqué mis razones desjustificando esta hipótesis, exponiendo así la DESQUERIDA para el debate de aquellos que se aferran a esta hipótesis equivocada.

Estos son los puntos que expresé contra la hipótesis.

  • La base para sostener esta hipótesis es la necesidad de métodos y reglas RESTRICTIVAS para hacer frente a los efectos de los malos hábitos y metodologías de software.

  • Los defensores del sentimiento " El patrón de interfaz constante es un mal uso de las interfaces" no pueden proporcionar otras razones que las causadas por la necesidad de hacer frente a los efectos de esos malos hábitos y prácticas.

  • Resuelve el problema fundamental.

  • Y luego, ¿por qué no hacer un uso completo y explotar todas las características del lenguaje de la estructura del lenguaje Java para su propia conveniencia? No se requieren chaquetas. ¿Por qué inventar reglas para bloquear su estilo de vida ineficaz para discriminar e incriminar estilos de vida más efectivos?

El tema fundamental

es la organización de la información. La información que media el proceso y el comportamiento de esa información deben entenderse primero, junto con las llamadas reglas de negocio, antes de diseñar o complementar soluciones al proceso. Este método de organización de la información se denominó normalización de datos hace algunas décadas.

Entonces, solo la ingeniería de una solución será posible porque alinear la granularidad y modularidad de los componentes de una solución con la granularidad y modularidad de los componentes de la información es la estrategia óptima.

Hay dos o tres obstáculos importantes para organizar la información.

  1. La falta de percepción de la necesidad de "normalización" del modelo de datos.

  2. Las declaraciones de EF Codd sobre la normalización de datos son erróneas, defectuosas y ambiguas.

  3. La última moda que se disfraza de ingeniería ágil es la noción equivocada de que no se debe planificar y condicionar la organización de los módulos con anticipación porque se puede refactorizar sobre la marcha. La refactorización y el cambio continuo sin verse obstaculizados por futuros descubrimientos se utilizan como excusa. Los descubrimientos esenciales del comportamiento de la información del proceso es entonces, mediante el uso de trucos contables para retrasar las ganancias y la puesta en activo, por lo que el conocimiento esencial y su tratamiento no se considera necesario ahora.

El uso de constantes de interfaz es una buena práctica.

No invente reglas ni emita ninguna fatwa en su contra solo porque ama sus hábitos de programación ad-hoc.

No prohíba la posesión de armas por el motivo de que hay personas que no saben cómo manejarlas o que son propensas a abusar de ellas.

Si las reglas que inventa están destinadas a principiantes de programación que no pueden codificar profesionalmente y que usted se cuenta entre ellos, dígalo, no declare su fatwa como aplicable a modelos de datos normalizados correctamente.

Un razonamiento tonto - ¿Los problemas del lenguaje Java no pretendían que las interfaces se usaran de esa manera?

No me importa cuáles fueron las intenciones originales de los padres fundadores para la Constitución de Estados Unidos. No me importan las intenciones no codificadas no escritas. Solo me importa lo que está codificado literariamente en la Constitución escrita y cómo puedo explotarlos para el funcionamiento efectivo de la sociedad.

Solo me importa lo que me permitan las especificaciones del lenguaje / plataforma Java y tengo la intención de explotarlas al máximo para proporcionarme un medio para expresar mis soluciones de software de manera eficiente y efectiva. No se requieren chaquetas.

El uso de las constantes Enum es realmente una práctica horrible.

Requiere escribir código adicional para asignar el parámetro al valor. El hecho de que los fundadores de Java no proporcionaran la asignación de valores de parámetros sin que usted escribiera ese código de asignación demuestra que las constantes de Enum son un uso no intencionado del lenguaje Java.

Sobre todo porque no se le anima a normalizar y componenteizar sus parámetros, habría una falsa impresión de que los parámetros mezclados en una bolsa Enum pertenecen a la misma dimensión.

Las constantes son contrato API

No olvides eso. Si diseñó y normalizó su modelo de datos, y estos incluyen constantes, esas constantes son contratos. Si no normalizó su modelo de datos, entonces debe ajustarse a las fatwas dadas sobre cómo practicar la codificación restrictiva para hacer frente a ese mal hábito.

Por lo tanto, las interfaces son una forma perfecta de implementar el contrato de Constants.

Una presunción extraña: ¿qué pasa si la interfaz se implementa inadvertidamente?

Sip. Cualquiera podría implementar inadvertidamente cualquier interfaz sin darse cuenta. Nada se interpondrá en el camino de estos programadores inadvertidos.

Diseñe y normalice su modelo de datos contra fugas

No coloque decretos restrictivos para proteger las presuntas malas prácticas que causan la filtración de parámetros no contratados / perdidos en la API. Resuelva el problema fundamental, en lugar de culpar a las constantes de interfaz.

No usar un IDE es una mala práctica

Un programador EFECTIVO y de funcionamiento normal no está allí para demostrar cuánto tiempo puede permanecer bajo el agua, qué tan lejos podría caminar en un calor abrasador o tormentas eléctricas húmedas. Ella debe usar una herramienta eficiente como un automóvil o autobús o al menos una bicicleta para llevar sus 10 millas al trabajo todos los días.

No imponga restricciones a los compañeros programadores solo porque tiene una obsesión de ascetismo esotérico con la programación sin IDE.

Un par de marcos están diseñados para ayudar a los programadores a seguir practicando malos hábitos de manera eficiente.

OSGI es un marco de este tipo. Y también lo es el decreto contra las Constantes de Interfaz.

Por tanto, la respuesta concluyente ...

Las constantes de interfaz son una forma eficaz y eficiente de colocar en el contrato componentes bien diseñados y normalizados de un modelo de datos.

Las constantes de interfaz en una interfaz privada con el nombre apropiado anidada en un archivo de clase también son una buena práctica para agrupar todas sus constantes privadas en lugar de dispersarlas por todo el archivo.

Bendito Geek
fuente
29
Todos sus puntos se pueden hacer sin las bromas, el sarcasmo y la emotividad. Stackoverflow no es una plataforma de blogs.
tkruse
1
"No me importa cuáles fueron las intenciones originales de los padres fundadores para la Constitución de los Estados Unidos. No me importan las intenciones no codificadas no escritas. Solo me importa lo que está codificado literalmente en la Constitución escrita y cómo puedo explotarlas para el funcionamiento eficaz de la sociedad ". - ¿No es buena alegoría?
Bendito Geek
"Requiere escribir código adicional para asignar un parámetro a un valor. El hecho de que los fundadores de Java no proporcionaron la asignación de valores de parámetros sin que usted escribiera ese código de asignación demuestra que las constantes de Enum son un uso no intencionado del lenguaje Java". ¿De qué otra manera obtendría la asignación de valores de parámetros sin escribir código adicional?
GabrielOshiro
Utilice constantes de interfaz. EXACTAMENTE.
Blessed Geek
9

Me encontré con esta vieja pregunta varias veces y la respuesta aceptada todavía me confunde. Después de pensarlo mucho, creo que esta pregunta se puede aclarar más.

¿Por qué utilizar Interface Constant?

Simplemente compárelos:

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

vs

public interface Constants {

    double PI = 3.14159;
    double PLANCK_CONSTANT = 6.62606896e-34;
}

Mismo uso. Mucho menos código.

¿Mala práctica?

Creo que la respuesta de @Pascal Thivent tiene un énfasis incorrecto, aquí está mi versión:

Poner miembros estáticos en una interfaz ( e implementar esa interfaz ) es una mala práctica.

La cita de Effective Java asume que la interfaz constante está siendo implementada por otros, lo que creo que no debería (y no sucederá) suceder.

Cuando crea una interfaz constante llamada algo así Constants, nadie debería implementarla. (aunque técnicamente posible, que es el único problema aquí)

No sucederá en la biblioteca estándar

La biblioteca estándar no puede permitirse ningún posible mal uso del diseño, por lo que no verá ninguno allí.

Sin embargo , para los proyectos diarias de los desarrolladores normales, utilizando la interfaz de constantes es mucho más fácil porque usted no necesita preocuparse de static, final, empty constructor, etc, y que no causa ningún problema de diseño malo. El único inconveniente que se me ocurre es que todavía tiene el nombre de "interfaz", pero nada más que eso.

Debate sin fin

Al final, creo que todos están citando libros y dando opiniones y justificaciones a sus posiciones. No es una excepción para mí. Quizás la decisión aún dependa de los desarrolladores de cada proyecto. Siga adelante para usarlo si se siente cómodo. Lo mejor que podemos hacer es que sea coherente durante todo el proyecto .

Nakamura
fuente
"Poner miembros estáticos en una interfaz (e implementar esa interfaz) es una mala práctica". No, no lo es
Lloviendo
El modificador publictambién se puede omitir ya que es una interfaz, por lo que simplemente ¡El double PI = 3.14159;uso de Constants.PIno necesita que la clase lo use para implementar la Constantsinterfaz! Creo que el enfoque de la interfaz es mucho más limpio en términos de uso, en mi humilde opinión
krozaine
@krozaine Actualizado. Gracias por el recordatorio. Referencia para quien tenga dudas: "Todos los valores constantes definidos en una interfaz son implícitamente públicos, estáticos y finales". - docs.oracle.com/javase/tutorial/java/IandI/interfaceDef.html
Nakamura
6

Joshua Bloch, "Eficaz Java - Guía del lenguaje de programación":

El patrón de interfaz constante es un mal uso de las interfaces. Que una clase use algunas constantes internamente es un detalle de implementación. La implementación de una interfaz constante hace que este detalle de implementación se filtre en la API exportada de la clase. No tiene ninguna importancia para los usuarios de una clase que la clase implemente una interfaz constante. De hecho, incluso puede confundirlos. Peor aún, representa un compromiso: si en una versión futura se modifica la clase para que ya no necesite usar las constantes, aún debe implementar la interfaz para asegurar la compatibilidad binaria. Si una clase no final implementa una interfaz constante, todas sus subclases tendrán sus espacios de nombres contaminados por las constantes en la interfaz.

apilador
fuente
Literalmente no agregó nada de valor que no se haya dicho ya.
Donal Fellows
2

Hay respuestas que son muy razonables.

Pero tengo algunas ideas sobre esta pregunta. (puede estar mal)

En mi opinión, los campos en una interfaz, no deben ser constantes para todo el proyecto, son solo medios para la interfaz y las interfaces la extienden y las clases que implementan estas interfaces o tienen una relación cercana con ellas. Deben usarse dentro de un rango determinado, no global.

Zhili
fuente
De hecho, deberían usarse dentro de esas clases de implementación.
lloviendo
2

Dos puntos sobre la interfaz:

  • Una interfaz describe un subconjunto de lo que puede hacer un objeto que lo implementa. (Esta es la intuición)

  • Una interfaz describe constantes comunes seguidas de objetos que la implementan.

    • Estas constantes comunes están destinadas a que el cliente las conozca para saber más sobre estos objetos.
    • Entonces, la interfaz de constantes es contraintuitiva para definir constantes globales , ya que la interfaz se usa para describir algunos objetos , no todos los objetos / ningún objeto (considere el significado de global ).

Entonces creo que si interfaz de constantes no se usa para constantes globales , entonces es aceptable:

  • Si estos constantes comunes tienen buenos nombres, recomendarán al implementador que las use (vea mi primer punto para el ejemplo a continuación)
  • Si una clase quiere sincronizarse con esas clases siguiendo la especificación, solo implementseso (y, por supuesto, use estas constantes comunes en la implementación).

Ejemplo:

interface Drawable {

    double GOLDEN_RATIO = 1.618033988;
    double PI = 3.141592653;
    ...

    // methods
    ...
}

public class Circle implements Drawable {
    ...
    public double getCircumference() {
        return 2 * PI * r;
    }
}

void usage() {

    Circle circle = new Circle(radius: 3.0);
    double maxRadius = 5.0;

    if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
        ...
    }

}

En este ejemplo:

  • De Circle implements Drawable, inmediatamente se sabe que Circleprobablemente se ajusta a las constantes definidas en Drawable, de lo contrario tienen que elegir un nombre peor que los buenosPI y GOLDEN_RATIOya se ha tomado!
  • Solo estos Drawableobjetos se ajustan a lo específico PIy GOLDEN_RATIOdefinido en Drawable, puede haber objetos que no Drawabletengan diferente precisión de pi y proporción áurea.
Lloviendo
fuente
¿Entendí mal tu respuesta o no entendiste el propósito de Interface? Una interfaz NO debe ser un subconjunto. Una interfaz es un contrato, que cualquiera que se suscriba al contrato debe proporcionar la interacción especificada por ese contrato. El único uso válido de la interfaz es utilizarla para declarar / cumplir un contrato.
Blessed Geek
@BlessedGeek Cumples un contrato, entonces la habilidad descrita en el contrato es un subconjunto de lo que puedes hacer.
Lloviendo
1

La javax.swing.SwingConstantsinterfaz es un ejemplo que tiene campos estáticos que se utilizan entre las clases de swing. Esto le permite usar fácilmente algo como

  • this.add(LINE_START, swingcomponent);
  • this.add(this.LINE_START, swingcomponent); o
  • this.add(SwingComponents.LINE_START, swingcomponent);

Sin embargo, esta interfaz no tiene métodos ...

Progman
fuente
1

Me encontré con esta pregunta y pensé en agregar algo que no se mencionó. En general, estoy de acuerdo con la respuesta de Pascal aquí . Sin embargo, no creo que las constantes en una interfaz sean "siempre" un antipatrón.

Por ejemplo, si las constantes que está definiendo son parte de un contrato para esa interfaz, creo que la interfaz es un gran lugar para las constantes. En algunos casos, simplemente no es apropiado validar de forma privada sus parámetros sin exponer el contrato a los usuarios de su implementación. Sin un contrato de cara al público, los usuarios solo pueden adivinar con qué está validando, salvo descompilar la clase y leer su código.

Entonces, si implementa una interfaz y la interfaz tiene las constantes que usa para garantizar sus contratos (como rangos enteros, por ejemplo), entonces un usuario de su clase puede estar seguro de que está usando la instancia de la interfaz correctamente al verificar las constantes en la interfaz sí mismos. Esto sería imposible si las constantes fueran privadas para su implementación o si su implementación fuera un paquete privado o algo así.

Akagixxer
fuente
1
El problema con las interfaces y constantes de la forma en que lo describe, puede agregar una constante a una interfaz, pero no hay un enlace que obligue al consumidor de su API a usar esa constante.
Daniel
@Daniel: voté a favor de tu comentario, pero ahora tengo una buena explicación para tu pregunta: "no hay ningún vínculo que obligue al consumidor de tu API a usar esa constante", pero ahora el cliente ya no puede usar CONSTANT_NAME porque ha sido usado, lo cual es una buena señal para mí!
Lloviendo
Entonces, el nombre de la constante no está disponible en su clase, pero eso supone que voy a nombrar la constante exactamente de la misma manera. Usar una interfaz para representar constantes sigue siendo una falacia, una interfaz es un contrato para una API. De ninguna manera debe usarse para representar valores constantes.
Daniel
-1

Utilizo constantes de interfaz cuando trato con constantes compartidas entre clases.

public interface TestConstants
{
    String RootLevelConstant1 = "RootLevelConstant1";

    interface SubGroup1
    {
        String SubGroupConstant1 = "SubGroup1Constant1";
        String SubGroupConstant2 = "SubGroup1Constant2";
    }

    interface SubGroup2
    {
        String SubGroupConstant1 = "SubGroup2Constant1";
        String SubGroupConstant2 = "SubGroup2Constant2";
    }
}

La agrupación es un gran activo, especialmente con un gran conjunto de constantes.

Para usarlos, simplemente encadénelos:

System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);
jared
fuente
Yo estaría de acuerdo. Básicamente, hace lo mismo que la clase abstracta pública con campos finales estáticos públicos, pero en muchas menos palabras. Todo lo que necesita es asegurarse de que todos los desarrolladores de su equipo sigan las buenas prácticas y no implementen estas interfaces.
Yahor
1
Esto es horrible porque puede hacer exactamente lo mismo con las clases, acceder de la misma manera, además de hacer que las clases sean definitivas y sus constructores privados (si realmente desea solo una bolsa de constantes juntas). Además, evita que la gente amplíe su clase. No puede evitar que la gente implemente su interfaz, ¿verdad?
GabrielOshiro
1
¿Por qué hacer en una clase lo que se puede hacer en una interfaz? ¿Cómo puedo evitar que la gente implemente CUALQUIER interfaz inadvertidamente? Es la pregunta. ¿Por qué escoges las constantes de interfaz?
Blessed Geek
-2

Los campos deben declararse en una interfaz para que sean más fáciles de compartir y puedan ser referenciados sin introducir un acoplamiento adicional.

Fuente: Estilo de codificación de las herramientas de desarrollo de Java

Mente maestra
fuente
tal vez antes de java6. pero eso es mayormente irrelevante hoy.
tkruse
Y el vínculo está roto. Codepro ya no existe.
Stephen C