¿Cuál es la mejor manera de implementar constantes en Java? [cerrado]


372

He visto ejemplos como este:

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

y supuse que podría tener una clase de Constantes para envolver constantes, declarándolas estáticas como finales. Prácticamente no conozco Java en absoluto y me pregunto si esta es la mejor manera de crear constantes.



Respuestas:


403

Eso es perfectamente aceptable, probablemente incluso el estándar.

(public/private) static final TYPE NAME = VALUE;

donde TYPEes el tipo, NAMEes el nombre en mayúsculas con guiones bajos para espacios y VALUEes el valor constante;

Recomiendo NO poner sus constantes en sus propias clases o interfaces.

Como nota al margen: las variables que se declaran finales y son mutables aún se pueden cambiar; sin embargo, la variable nunca puede apuntar a un objeto diferente.

Por ejemplo:

public static final Point ORIGIN = new Point(0,0);

public static void main(String[] args){

    ORIGIN.x = 3;

}

Eso es legal y ORIGINsería un punto en (3, 0).


19
Incluso puede 'importar MaxSeconds.MAX_SECONDS estáticos;' para que no tenga que deletrearlo MaxSeconds.MAX_SECONDS
Aaron Maenpaa

23
El comentario anterior sobre la importación estática solo se aplica a Java 5+. Algunos piensan que la taquigrafía no vale la posible confusión sobre el origen de la constante, cuando se lee un código largo, MaxSeconds.MAX_SECONDS puede ser más fácil de seguir que subir y mirar las importaciones.
MetroidFan2002

55
Debido a que puede cambiar el objeto como lo ha demostrado jjnguy, es mejor si sus constantes son objetos inmutables o simplemente primitivas / cadenas.
marcospereira

14
Si está leyendo esta pregunta, lea las siguientes dos respuestas a continuación antes de tomar esta respuesta demasiado en serio, a pesar de ser aceptado, es controvertido si no está mal.
pez orb

3
@jjnguy no estás equivocado, pero si leo solo la pregunta y las primeras líneas de tu respuesta, tendría la impresión de que "una clase de constantes" es "perfectamente aceptable, probablemente incluso el estándar". Esa noción está mal.
Zach Lysobey

235

Recomiendo encarecidamente no tener una sola clase de constantes. Puede parecer una buena idea en ese momento, pero cuando los desarrolladores se niegan a documentar las constantes y la clase crece para abarcar más de 500 constantes que no están relacionadas entre sí (están relacionadas con aspectos completamente diferentes de la aplicación), esto generalmente se convierte en un archivo de constantes completamente ilegible. En lugar:

  • Si tiene acceso a Java 5+, use enumeraciones para definir sus constantes específicas para un área de aplicación. Todas las partes del área de aplicación deben referirse a enumeraciones, no a valores constantes, para estas constantes. Puede declarar una enumeración similar a cómo declara una clase. Las enumeraciones son quizás la característica más útil (y posiblemente la única) de Java 5+.
  • Si tiene constantes que solo son válidas para una clase en particular o una de sus subclases, declare como protegidas o públicas y colóquelas en la clase superior de la jerarquía. De esta manera, las subclases pueden acceder a estos valores constantes (y si otras clases acceden a ellos a través del público, las constantes no solo son válidas para una clase en particular ... lo que significa que las clases externas que usan esta constante pueden estar demasiado estrechamente acopladas a clase que contiene la constante)
  • Si tiene una interfaz con comportamiento definido, pero los valores devueltos o los valores de argumento deben ser particulares, es perfectamente aceptable definir constantes en esa interfaz para que otros implementadores tengan acceso a ellas. Sin embargo, evite crear una interfaz solo para contener constantes: puede volverse tan mala como una clase creada solo para contener constantes.

12
totalmente de acuerdo ... esto puede documentarse como un antipatrón clásico para grandes proyectos.
Das

30
Fuera de tema, pero ... Los genéricos ciertamente no son perfectos, pero creo que podría ser un buen argumento para que sean una característica útil de Java 5 :)
Martin McNulty

3
@ ŁukaszL. La pregunta en sí misma se basa realmente en la opinión (siempre que surge "lo mejor", generalmente es una cuestión de opinión), por lo que la respuesta es una respuesta válida a esta pregunta. He dado una respuesta sobre qué (sí, creo que es, así que sí, es una opinión, porque de nuevo "lo mejor" cambia con el tiempo y generalmente se basa en la opinión) es la mejor manera de implementar constantes en Java.
MetroidFan2002

1
Ninguna de las opciones anteriores le da una verdadera variable global. ¿Qué sucede si tengo algo que se usa en todas partes pero que no es una enumeración? ¿Hago una enumeración de una sola cosa?
markthegrea

1
Si necesita una constante global que abarque todos los módulos, probablemente haya algo mal con su estrategia de diseño. Si realmente necesita una constante global, haga una clase final pública para él en el paquete de nivel superior y péguelo allí. Luego, elimínelo tan pronto como se dé cuenta de que no todas sus clases realmente necesitan esa constante, y muévala al paquete que más lo referencia. Puede compartir una constante entre paquetes, pero es un olfato de código requerir una constante global que no sea un tipo enumerado, ya que los tipos enumerados pueden tener comportamiento, pero una cadena es una cadena, un int es un int, etc.
MetroidFan2002

120

Es un MALA PRÁCTICA usar interfaces solo para mantener constantes ( Josh Bloch lo denomina patrón de interfaz constante ). Esto es lo que aconseja Josh:

Si las constantes están fuertemente vinculadas a una clase o interfaz existente, debe agregarlas a la clase o interfaz. Por ejemplo, todas las clases primitivas numéricas en caja, como Integer y Double, exportan constantes MIN_VALUE y MAX_VALUE. Si las constantes se ven mejor como miembros de un tipo enumerado, debe exportarlas con un tipo de enumeración . De lo contrario, debe exportar las constantes con una clase de utilidad no instantable.

Ejemplo:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

Sobre la convención de nomenclatura:

Por convención, dichos campos tienen nombres que consisten en letras mayúsculas, con palabras separadas por guiones bajos. Es crítico que estos campos contengan valores primitivos o referencias a objetos inmutables.


23
Si vas a llamar a algo mala práctica, ¿quizás deberías explicar por qué crees que es?
GlennS

14
Esta es una publicación anterior, pero es mejor usar la abstractnotación para la clase en lugar del constructor privado.
Xtreme Biker

55
Matt, aunque la recomendación del motorista no es falsa, yo recomendaría las clases finales, en lugar de las clases abstractas. El punto del motorista al decir que era que querías asegurarte de que tu clase de constantes no sea modificable. Entonces, al marcarlo como final, no está permitiendo que se subclasifique o se instancia. Esto también ayuda a encapsular su funcionalidad estática y no permite que otros desarrolladores lo subclasifiquen y lo hagan hacer cosas para las que no fue diseñado.
liltitus27

77
@XtremeBiker Marcar la clase en abstractlugar de un constructor privado no evita por completo la creación de instancias, porque se podría subclasificar e instanciar la subclase (no es una buena idea hacerlo, pero es posible). @ToolmakerSteve No puede subclasificar una clase con un constructor privado (al menos no sin un gran truco malo), porque el constructor de la subclase necesita llamar al constructor (ahora privado) de su superclase. Entonces, marcarlo finales innecesario (pero quizás más explícito).
Importar este

3
Es aún peor usar la clase solo para mantener constantes. Si nunca quieres crear un objeto de esa clase, ¿por qué usas la clase regular en primer lugar?
MaxZoom

36

En Java efectivo (2a edición), se recomienda que use enumeraciones en lugar de entradas estáticas para constantes.

Aquí hay una buena reseña sobre las enumeraciones en Java: http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

Tenga en cuenta que al final de ese artículo la pregunta planteada es:

Entonces, ¿cuándo deberías usar enumeraciones?

Con una respuesta de:

Cada vez que necesite un conjunto fijo de constantes


21

Solo evita usar una interfaz:

public interface MyConstants {
    String CONSTANT_ONE = "foo";
}

public class NeddsConstant implements MyConstants {

}

Es tentador, pero viola la encapsulación y difumina la distinción de las definiciones de clase.


1
De hecho, las importaciones estáticas son mucho más preferibles.
Aaron Maenpaa

1
Esta práctica es un uso extraño de las interfaces, que están destinadas a establecer los servicios proporcionados por una clase.
Rafa Romero

1
No estoy en desacuerdo con evitar el uso de la interfaz para constantes, pero creo que su ejemplo es engañoso. No necesita implementar la interfaz para obtener acceso a la constante porque es implícitamente estática, pública y final. Entonces, es más simple de lo que has descrito aquí.
djangofan

Eso es cierto ... está violando la encapsulación, prefiero usar la clase Constant final que parece más orientada a objetos y preferible que la interfaz O la enumeración . Nota: Enum se puede evitar en caso de que Android no sea necesario.
Código

19

Yo uso el siguiente enfoque:

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

Que, por ejemplo, solía Constants.DB.Connection.URLser constante. Se ve más "objeto orientado" en cuanto a mí.


44
Interesante, pero engorroso. ¿Por qué no crearías constantes en la clase más estrechamente asociada con ellas, como recomiendan otros? Por ejemplo, en su código DB en otro lugar, ¿tiene una clase base para sus conexiones? Por ejemplo, "ConnectionBase". Entonces puedes poner las constantes allí. Es probable que cualquier código que funcione con conexiones ya tenga una importación tal que simplemente pueda decir "ConnectionBase.URL" en lugar de "Constants.DB.Connection.URL".
ToolmakerSteve

3
@ToolmakerSteve Pero, ¿qué pasa con las constantes generales que pueden usar varias clases? por ejemplo, estilos, URL de servicios web, etc.
Daniel Gomez Rico

Poner todas las constantes en una clase tiene una ventaja: mantenimiento. Siempre sabes exactamente dónde encontrar las constantes. No digo que esto mejore esta técnica, solo estoy proporcionando una ventaja. Y lo que ha hecho @ albus.ua es categorizar sus constantes, lo cual es una buena idea, especialmente si la clase de constantes contiene muchos valores constantes. Esta técnica ayudará a mantener la clase manejable y ayuda a describir mejor el propósito de la constante.
Nelda.techspiress

17

Crear constantes finales estáticas en una clase separada puede meterte en problemas. El compilador de Java realmente optimizará esto y colocará el valor real de la constante en cualquier clase que lo haga referencia.

Si luego cambia la clase 'Constantes' y no realiza una compilación difícil en otras clases que hacen referencia a esa clase, terminará con una combinación de valores antiguos y nuevos que se están utilizando.

En lugar de pensar en estas como constantes, piense en ellas como parámetros de configuración y cree una clase para administrarlas. Haga que los valores sean no finales e incluso considere usar getters. En el futuro, si determina que algunos de estos parámetros deberían ser configurables por el usuario o el administrador, será mucho más fácil hacerlo.


+1 por esta excelente advertencia. (Si no puede garantizar que sea una constante permanente, considere un getter, como menciona big_peanut_horse). Lo mismo se aplica con const en C #, por cierto: msdn.microsoft.com/en-us/library/e6w8fe1b.aspx
Jon Coombs

13

El error número uno que puede cometer es crear una clase accesible globalmente llamada con un nombre genérico, como Constantes. Esto simplemente se llena de basura y pierde toda capacidad de averiguar qué parte de su sistema usa estas constantes.

En cambio, las constantes deben ir a la clase que las "posee". ¿Tienes una constante llamada TIMEOUT? Probablemente debería ir a su clase de Comunicaciones () o Conexión (). MAX_BAD_LOGINS_PER_HOUR? Entra en Usuario (). Y así sucesivamente y así sucesivamente.

El otro uso posible son los archivos .properties de Java cuando las "constantes" se pueden definir en tiempo de ejecución, pero no son fácilmente modificables por el usuario. Puede empaquetarlos en sus archivos .jars y hacer referencia a ellos con Class resourceLoader.


Y, por supuesto, nunca querrá acceder a una constante de más de una clase, o evitar el desorden en la parte superior de una clase.
pez orb

6

Ese es el camino correcto a seguir.

En general, las constantes no se guardan en clases separadas de "Constantes" porque no se pueden descubrir. Si la constante es relevante para la clase actual, mantenerla allí ayuda al próximo desarrollador.



5

Prefiero usar getters en lugar de constantes. Esos captadores pueden devolver valores constantes, por ejemplopublic int getMaxConnections() {return 10;} , pero cualquier cosa que necesite la constante pasará por un captador.

Una ventaja es que si su programa supera la constante (se da cuenta de que debe ser configurable), puede cambiar la forma en que el captador devuelve la constante.

El otro beneficio es que para modificar la constante no tiene que volver a compilar todo lo que la usa. Cuando hace referencia a un campo final estático, el valor de esa constante se compila en cualquier código de bytes que lo haga referencia.


55
Compilar bien las clases de referencia no es una carga en el siglo XXI. Y nunca debe usar el modelo de acceso / mutador (getter / setter) para otras cosas que no sean acceder y mutar variables miembro. Conceptualmente, las constantes deben ser de naturaleza inmediata, mientras que los captadores / establecedores (ambos) están destinados a administrar el estado . Además, solo estás pidiendo confusión: la gente no esperará que un captador produzca una simple constante.

5

Estoy de acuerdo en que usar una interfaz no es el camino a seguir. Evitar este patrón incluso tiene su propio elemento (# 18) en Java efectivo de Bloch .

Un argumento que hace Bloch contra el patrón de interfaz constante es que el uso de constantes es un detalle de implementación, pero la implementación de una interfaz para usarlos expone ese detalle de implementación en la API exportada.

El public|private static final TYPE NAME = VALUE;patrón es una buena forma de declarar una constante. Personalmente, creo que es mejor evitar hacer una clase separada para albergar todas tus constantes, pero nunca he visto una razón para no hacerlo, aparte de la preferencia personal y el estilo.

Si sus constantes se pueden modelar bien como una enumeración, considere la estructura de enumeración disponible en 1.5 o posterior.

Si está utilizando una versión anterior a la 1.5, aún puede obtener enumeraciones seguras de tipo mediante el uso de clases Java normales. (Vea este sitio para más información sobre eso).


Se pueden usar algunas constantes para llamar a una API. Por ejemplo, vea la interfaz org.springframework.transaction.TransactionDefinition. Tiene una lista de constantes como int PROPAGATION_REQUIRED = 0;
borjab

Sé que esto es viejo, pero el enlace al Bloque de Java efectivo está roto. ¿Podría proporcionar otra u otra referencia que respalde que "usar una interfaz no es el camino a seguir", por favor?
Nelda.techspiress

4

En base a los comentarios anteriores, creo que este es un buen enfoque para cambiar la clase constante global pasada de moda (que tiene variables finales estáticas públicas) a su equivalente enum de una manera como esta:

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

Entonces puedo referirlos a me gusta:

Constants.StringConstant.DB_HOST

44
¿Por qué? ¿Cómo es eso una mejora? Cada referencia es ahora engorrosa (Constants.StringConstant.whatever). En mi humilde opinión, vas por un camino lleno de baches aquí.
ToolmakerSteve

3

Un buen diseño orientado a objetos no debería necesitar muchas constantes disponibles públicamente. La mayoría de las constantes deben encapsularse en la clase que las necesita para hacer su trabajo.


1
O inyectado en esa clase a través del constructor.
WW.

2

Hay una cierta cantidad de opinión para responder esto. Para empezar, las constantes en java generalmente se declaran públicas, estáticas y finales. A continuación se detallan los motivos:

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

Nunca usaría una interfaz para un objeto / acceso CONSTANTES simplemente porque generalmente se espera que las interfaces se implementen. ¿No se vería esto gracioso?

String myConstant = IMyInterface.CONSTANTX;

En su lugar, elegiría entre algunas formas diferentes, en función de algunas pequeñas compensaciones, por lo que depende de lo que necesite:

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe

2

¿Cuál es la mejor manera de implementar constantes en Java?

Un enfoque que realmente deberíamos evitar : usar interfaces para definir constantes.

Crear una interfaz específicamente para declarar constantes es realmente lo peor: derrota la razón por la cual se diseñaron las interfaces: definir el contrato de método (s).

Incluso si ya existe una interfaz para abordar una necesidad específica, declarar las constantes en ellas realmente no tiene sentido ya que las constantes no deberían formar parte de la API y el contrato proporcionado a las clases de clientes.


Para simplificar, tenemos en general 4 enfoques válidos .

Con static final String/Integercampo:

  • 1) usando una clase que declara constantes dentro pero no solo.
  • 1 variante) creando una clase dedicada a declarar solo constantes.

Con Java 5 enum:

  • 2) declarar la enumeración en una clase de propósito relacionada (como una clase anidada).
  • 2 variante) creando la enumeración como una clase independiente (así definida en su propio archivo de clase).

TLDR: ¿Cuál es la mejor manera y dónde ubicar las constantes?

En la mayoría de los casos, la forma enum es probablemente más fina que la static final String/Integerforma y personalmente creo que la static final String/Integerforma debería usarse solo si tenemos buenas razones para no usar enumeraciones.
Y sobre dónde deberíamos declarar los valores constantes, la idea es buscar si hay una sola clase existente que posea una cohesión funcional específica y fuerte con valores constantes. Si encontramos tal clase, deberíamos usarla como el titular de las constantes . De lo contrario, la constante no debe estar asociada a ninguna clase en particular.


static final String/ static final Integerversusenum

El uso de enumeraciones es realmente una forma de considerarlo.
Las enumeraciones tienen una gran ventaja sobre el campo Stringo Integerconstante.
Establecen una restricción de compilación más fuerte. Si define un método que toma la enumeración como parámetro, solo puede pasar un valor de enumeración definido en la clase de enumeración (o nulo).
Con String e Integer puede sustituirlos por cualquier valor de tipo compatible y la compilación estará bien incluso si el valor no es una constante definida en los campos static final String/ static final Integer.

Por ejemplo, debajo de dos constantes definidas en una clase como static final Stringcampos:

public class MyClass{

   public static final String ONE_CONSTANT = "value";
   public static final String ANOTHER_CONSTANT = "other value";
   . . .
}

Aquí un método que espera tener una de estas constantes como parámetro:

public void process(String constantExpected){
    ...    
}

Puedes invocarlo de esta manera:

process(MyClass.ONE_CONSTANT);

o

process(MyClass.ANOTHER_CONSTANT);

Pero ninguna restricción de compilación le impide invocarlo de esta manera:

process("a not defined constant value");

Tendría el error solo en tiempo de ejecución y solo si realiza una comprobación a la vez del valor transmitido.

Con enum, no se requieren comprobaciones ya que el cliente solo puede pasar un valor enum en un parámetro enum.

Por ejemplo, aquí hay dos valores definidos en una clase enum (tan constante fuera de la caja):

public enum MyEnum {

    ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");

    private String value;

    MyEnum(String value) {
       this.value = value;
    }
         ...
}

Aquí un método que espera tener uno de estos valores de enumeración como parámetro:

public void process(MyEnum myEnum){
    ...    
}

Puedes invocarlo de esta manera:

process(MyEnum.ONE_CONSTANT);

o

process(MyEnum.ANOTHER_CONSTANT);

Pero la compilación nunca le permitirá invocarlo de esta manera:

process("a not defined constant value");

¿Dónde debemos declarar las constantes?

Si su aplicación contiene una sola clase existente que posee una cohesión funcional específica y fuerte con los valores constantes, el 1) y el 2) parecen más intuitivos.
En general, facilita el uso de las constantes si se declaran en la clase principal que las manipula o que tienen un nombre muy natural para adivinar que lo encontraremos dentro.

Por ejemplo, en la biblioteca JDK, los valores exponenciales y constantes pi se declaran en una clase que declara no solo declaraciones constantes ( java.lang.Math).

   public final class Math {
          ...
       public static final double E = 2.7182818284590452354;
       public static final double PI = 3.14159265358979323846;
         ...
   }

Los clientes que usan funciones matemáticas dependen a menudo de la Mathclase. Por lo tanto, pueden encontrar constantes con bastante facilidad y también pueden recordar dónde Ey PIse definen de una manera muy natural.

Si su aplicación no contiene una clase existente que tenga una cohesión funcional muy específica y fuerte con los valores constantes, las formas 1 variante) y 2 variante parecen más intuitivas.
En general, no facilita el uso de las constantes si se declaran en una clase que las manipula, mientras que también tenemos otras 3 o 4 clases que las manipulan tanto y ninguna de estas clases parece ser más natural que otras. hospedar valores constantes.
Aquí, definir una clase personalizada para contener solo valores constantes tiene sentido.
Por ejemplo, en la biblioteca JDK, la java.util.concurrent.TimeUnitenumeración no se declara en una clase específica ya que en realidad no hay una sola clase específica JDK que aparezca como la más intuitiva para contenerla:

public enum TimeUnit {
    NANOSECONDS {
      .....
    },
    MICROSECONDS {
      .....
    },
    MILLISECONDS {
      .....
    },
    SECONDS {
      .....
    },
      .....
}      

Muchas clases declaradas en java.util.concurrentel uso de ellos: BlockingQueue, ArrayBlockingQueue<E>, CompletableFuture, ExecutorService, ... y realmente ninguno de ellos parece más apropiado para mantener la enumeración.


1

Una constante, de cualquier tipo, puede declararse creando una propiedad inmutable que dentro de una clase (que es una variable miembro con el finalmodificador). Por lo general, también se proporcionan los modificadores staticy public.

public class OfficePrinter {
    public static final String STATE = "Ready";  
}

Existen numerosas aplicaciones donde el valor de una constante indica una selección de una n-tupla (por ejemplo, enumeración ) de opciones. En nuestro ejemplo, podemos elegir definir un Tipo enumerado que restringirá los posibles valores asignados (es decir , seguridad de tipo mejorada ):

public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}

1

Una sola clase de constantes genéricas es una mala idea. Las constantes deben agruparse con la clase con la que están más relacionadas lógicamente.

En lugar de usar variables de cualquier tipo (especialmente enumeraciones), sugeriría que use métodos. Cree un método con el mismo nombre que la variable y haga que devuelva el valor que asignó a la variable. Ahora elimine la variable y reemplace todas las referencias con llamadas al método que acaba de crear. Si cree que la constante es lo suficientemente genérica como para no tener que crear una instancia de la clase solo para usarla, entonces haga que el método constante sea un método de clase.


1

FWIW, un valor de tiempo de espera en segundos probablemente debería ser una configuración (leída desde un archivo de propiedades o mediante inyección como en Spring) y no una constante.


1

Cuál es la diferencia

1)

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2)

public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

y usar MyGlobalConstants.TIMEOUT_IN_SECSdonde sea que necesitemos esta constante. Creo que ambos son iguales.


1
Esto parece ser esencialmente un comentario en respuesta a la respuesta que dio bincob. Creo que se comportan de manera muy similar, pero el punto de bincob es que de ninguna manera definen una interfaz. Y la sugerencia era agregar constantes a clases reales, no crear una clase de esqueleto MyGlobalConstants. (Aunque esto ocasionalmente tiene sentido; use una "clase estática" al tener constantes estáticas y un constructor privado para evitar la creación de instancias; vea java.lang.math.) Considere usar enum.
Jon Coombs

También poner "final" en la declaración de clase evitará subclases. (En C # podría hacer "estático", que significa "resumen final", por lo que no es necesario un constructor privado explícito).
Jon Coombs

Sí, @JonCoombs, pero "final" no impide que sea una instanciación directa. Y Java no permite que tanto el final como el abstracto aparezcan juntos para las clases, por lo tanto, el constructor privado que aparece interminablemente para evitar tanto la instanciación como la subclasificación. No tengo idea de por qué se rechaza el "resumen final", aparte de que a primera vista parece contradictorio en la forma en que se lee: "no se puede subclasificar, pero esta clase debe ser subclasificada".

0

No llamaría a la clase lo mismo (aparte de la carcasa) como la constante ... Tendría como mínimo una clase de "Configuración", "Valores" o "Constantes", donde vivirían todas las constantes. Si tengo un gran número de ellos, los agruparía en clases constantes lógicas (UserSettings, AppSettings, etc.)


Tener una clase llamada Constantes fue lo que planeé hacer, ese fue solo un pequeño ejemplo que encontré.
mk.

0

Para ir un paso más allá, puede colocar constantes usadas globalmente en una interfaz para que puedan usarse en todo el sistema. P.ej

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

Pero no lo implemente. Simplemente refiérase a ellos directamente en código a través del nombre de clase completamente calificado.


El punto sobre declararlos en una interfaz (y no implementarla) es que puede perderse la "final estática pública".
Tom Hawtin - tackline

99
Las interfaces son para definir un contrato de comportamiento, no un mecanismo de conveniencia para mantener constantes.
John Topley

@JohnTopley Sí, pero funciona. ;)
trusktr

0

Para Constantes, Enum es una mejor opción en mi humilde opinión. Aquí hay un ejemplo

clase pública myClass {

public enum myEnum {
    Option1("String1", 2), 
    Option2("String2", 2) 
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}

0

Una de las formas en que lo hago es creando una clase 'Global' con los valores constantes y haciendo una importación estática en las clases que necesitan acceso a la constante.


0

static finales mi preferencia, solo usaría un enumsi el elemento fuera realmente enumerable.


0

yo suelo static final a declarar constantes e ir con los nombres ALL_CAPS notación. He visto bastantes instancias de la vida real donde todas las constantes se agrupan en una interfaz. Algunas publicaciones lo han llamado acertadamente una mala práctica, principalmente porque no es para eso que sirve una interfaz. Una interfaz debe hacer cumplir un contrato y no debe ser un lugar para colocar constantes no relacionadas. Ponerlo junto en una clase que no se pueda instanciar (a través de un constructor privado) también está bien si la semántica constante no pertenece a una clase específica ( es). Siempre pongo una constante en la clase con la que está más relacionada, porque eso tiene sentido y también es fácil de mantener.

Las enumeraciones son una buena opción para representar un rango de valores, pero si está almacenando constantes independientes con énfasis en el valor absoluto (p. Ej., TIEMPO DE ESPERA = 100 ms), simplemente puede optar por el static finalenfoque.


0

Estoy de acuerdo con lo que la mayoría dice, es mejor usar enumeraciones cuando se trata de una colección de constantes. Sin embargo, si está programando en Android, hay una solución mejor: Anotación IntDef .

@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();

La anotación IntDef es superior a las enumeraciones de una manera simple, ocupa mucho menos espacio, ya que es simplemente un marcador de tiempo de compilación. No es una clase, ni tiene la propiedad de conversión automática de cadenas.


Si bien estoy de acuerdo con la mejor práctica de no usar la interfaz solo en Java y evitar la enumeración en Android, este reemplazo en Android solo funciona cuando está utilizando una pequeña cantidad de campos. Es un ahorro significativo de memoria, pero puede generar hinchazón, ya que es una interfaz por campo en una enumeración mixta. Por ejemplo, si tengo una enumeración mixta que define lo que un objeto toma en su constructor, no puedo guardar nada con este enfoque, y vuelvo a las constantes seguras sin tipo porque en Android, no quieres demasiadas clases / interfaces.
Droid Teahouse

0

Es MALO hábito y una práctica terriblemente molesta citar a Joshua Bloch sin comprender el fundamentalismo básico de la zona cero.

No he leído nada Joshua Bloch, así que tampoco

  • el es un programador terrible
  • o las personas hasta ahora a las que encuentro citando (Joshua es el nombre de un niño que presumo) simplemente están usando su material como guiones religiosos para justificar sus indulgencias religiosas de software.

Como en el fundamentalismo bíblico, todas las leyes bíblicas pueden resumirse por

  • Ama la identidad fundamental con todo tu corazón y toda tu mente
  • Ama a tu prójimo como a ti mismo

y de manera similar, el fundamentalismo de la ingeniería de software puede resumirse en

  • Dedícate a los fundamentos de la zona cero con todo tu poder de programación y mente
  • y dedícate a la excelencia de tus compañeros programadores como lo harías por ti mismo.

Además, entre los círculos fundamentalistas bíblicos se dibuja un corolario fuerte y razonable.

  • Primero Amate a ti mismo. Porque si no te amas mucho, entonces el concepto "ama a tu prójimo como a ti mismo" no tiene mucho peso, ya que "cuánto te amas a ti mismo" es la línea de referencia sobre la cual amarías a los demás.

Del mismo modo, si no te respetas a ti mismo como programador y solo aceptas los pronunciamientos y las profecías de algún gurú de la programación SIN cuestionar los fundamentos, tus citas y tu confianza en Joshua Bloch (y similares) no tiene sentido. Y, por lo tanto, en realidad no respetarías a tus compañeros programadores.

Las leyes fundamentales de la programación de software.

  • la pereza es la virtud de un buen programador
  • debes hacer que tu vida de programación sea lo más fácil, perezosa y, por lo tanto, tan efectiva como sea posible
  • debe hacer que las consecuencias y las entrañas de su programación sean tan fáciles, perezosas y, por lo tanto, tan efectivas como sea posible para sus programadores vecinos que trabajan con usted y recogen sus entrañas de programación.

¿Las constantes de patrón de interfaz son un mal hábito?

¿Bajo qué leyes de programación fundamentalmente efectiva y responsable cae este edicto religioso?

Simplemente lea el artículo de Wikipedia sobre las constantes de patrón de interfaz ( https://en.wikipedia.org/wiki/Constant_interface ), y las tontas excusas que establece contra las constantes de patrón de interfaz.

  • Whatif-No IDE? ¿Quién en la tierra como programador de software no usaría un IDE? La mayoría de nosotros somos programadores que preferimos no tener que demostrar que tenemos un sobrevivencia machista y estético para evitar el uso de un IDE.

    • Además, espere un segundo proponentes de la programación micro-funcional como un medio para no necesitar un IDE. Espere hasta que lea mi explicación sobre la normalización del modelo de datos.
  • ¿Contamina el espacio de nombres con variables no utilizadas dentro del alcance actual? Podrían ser defensores de esta opinión

    • desconocen y necesitan la normalización del modelo de datos
  • El uso de interfaces para aplicar constantes es un abuso de las interfaces. Los defensores de tales tienen la mala costumbre de

    • sin ver que las "constantes" deben tratarse como un contrato. Y las interfaces se utilizan para hacer cumplir o proyectar el cumplimiento de un contrato.
  • Es difícil, si no imposible, convertir las interfaces en clases implementadas en el futuro. Hah .... hmmm ... ???

    • ¿Por qué querrías participar en un patrón de programación como tu subsistencia persistente? IOW, ¿por qué dedicarse a un hábito de programación tan AMBIVALENT y tan malo?

Cualesquiera que sean las excusas, NO HAY EXCUSA VÁLIDA cuando se trata de ingeniería de software FUNDAMENTAMENTE EFECTIVA para deslegitimar o, en general, desalentar el uso de constantes de interfaz.

No importa cuáles fueron las intenciones originales y los estados mentales de los padres fundadores que elaboraron la Constitución de los Estados Unidos. Podríamos debatir las intenciones originales de los padres fundadores, pero lo único que me importa son las declaraciones escritas de la Constitución de los Estados Unidos. Y es responsabilidad de cada ciudadano estadounidense explotar el fundamentalismo literario escrito, no las intenciones fundacionales no escritas, de la Constitución de los Estados Unidos.

Del mismo modo, no me importa lo que las intenciones "originales" de los fundadores de la plataforma Java y el lenguaje de programación tenían para la interfaz. Lo que me importa son las características efectivas que proporciona la especificación Java, y tengo la intención de explotar esas características al máximo para ayudarme a cumplir con las leyes fundamentales de la programación de software responsable. No me importa si se percibe que "viola la intención de las interfaces". No me importa lo que Gosling o alguien Bloch diga sobre la "forma correcta de usar Java", a menos que lo que digan no viole mi necesidad de cumplir con los fundamentos EFICAZmente.

Lo fundamental es la normalización del modelo de datos

No importa cómo se aloje o transmita su modelo de datos. Ya sea que use interfaces o enumeraciones o cualquier otra cosa, relacional o sin SQL, si no comprende la necesidad y el proceso de normalización del modelo de datos.

Primero debemos definir y normalizar el modelo de datos de un conjunto de procesos. Y cuando tenemos un modelo de datos coherente, SOLO podemos usar el flujo de proceso de sus componentes para definir el comportamiento funcional y el proceso bloquea un campo o ámbito de aplicaciones. Y solo entonces podemos definir la API de cada proceso funcional.

Incluso las facetas de la normalización de datos propuestas por EF Codd ahora se ven seriamente desafiadas y severamente desafiadas. Por ejemplo, su declaración sobre 1NF ha sido criticada por ser ambigua, desalineada y simplificada en exceso, al igual que el resto de sus declaraciones, especialmente en el advenimiento de los servicios de datos modernos, tecnología de transmisión y transmisión. En mi opinión, las declaraciones de EF Codd deben eliminarse por completo y diseñarse un nuevo conjunto de declaraciones más matemáticamente plausibles.

Una falla evidente de EF Codd's y la causa de su desalineación con la comprensión humana efectiva es su creencia de que los datos de dimensiones mutables y multidimensionales perceptibles humanamente pueden percibirse eficientemente a través de un conjunto de mapeos bidimensionales fragmentados.

Los fundamentos de la normalización de datos

Lo que EF Codd no pudo expresar.

Dentro de cada modelo de datos coherente, estos son el orden secuencial graduado de coherencia del modelo de datos a lograr.

  1. La unidad e identidad de las instancias de datos.
    • diseñe la granularidad de cada componente de datos, de modo que su granularidad esté en un nivel en el que cada instancia de un componente pueda identificarse y recuperarse de manera única.
    • ausencia de alias de instancia. es decir, no existen medios por los cuales una identificación produce más de una instancia de un componente.
  2. Ausencia de diafonía de instancia. No existe la necesidad de utilizar una o más instancias de un componente para contribuir a identificar una instancia de un componente.
  3. La unidad e identidad de los componentes / dimensiones de los datos.
    • Presencia de alias de componentes. Debe existir una definición mediante la cual un componente / dimensión pueda identificarse de manera única. Cuál es la definición primaria de un componente;
    • donde la definición primaria no resultará en exponer subdimensiones o componentes miembros que no son parte de un componente deseado;
  4. Medios únicos de negociación de componentes. Debe existir una, y solo una, dicha definición de eliminación de alias de componentes para un componente.
  5. Existe una, y solo una, interfaz de definición o contrato para identificar un componente padre en una relación jerárquica de componentes.
  6. Ausencia de diafonía de componentes. No existe la necesidad de utilizar un miembro de otro componente para contribuir a la identificación definitiva de un componente.
    • En dicha relación padre-hijo, la definición de identificación de un padre no debe depender de parte del conjunto de componentes miembros de un hijo. Un componente miembro de la identidad de un padre debe ser la identidad completa del niño sin tener que recurrir a la referencia de uno o todos los hijos de un niño.
  7. Preempt apariencias bimodales o multimodales de un modelo de datos.
    • Cuando existen dos definiciones candidatas de un componente, es una señal obvia de que existen dos modelos de datos diferentes que se mezclan como uno solo. Eso significa que hay incoherencia a nivel del modelo de datos, o el nivel de campo.
    • Un campo de aplicaciones debe usar uno y solo un modelo de datos, de manera coherente.
  8. Detectar e identificar la mutación del componente. A menos que haya realizado un análisis estadístico de componentes de gran cantidad de datos, probablemente no vea, o vea la necesidad de tratar, la mutación de componentes.
    • Un modelo de datos puede tener algunos de sus componentes mutados cíclica o gradualmente.
    • El modo puede ser rotación de miembros o rotación de transposición.
    • La mutación de rotación de miembros podría ser un intercambio distinto de componentes secundarios entre componentes. O donde se tendrían que definir componentes completamente nuevos.
    • La mutación transposicional se manifestaría como un miembro dimensional que muta en un atributo, viceversa.
    • Cada ciclo de mutación debe identificarse como un modo de datos distinto.
  9. Versionar cada mutación. De modo que pueda extraer una versión anterior del modelo de datos, cuando tal vez surja la necesidad de tratar una mutación del modelo de datos de 8 años.

En un campo o cuadrícula de aplicaciones de componentes entre servicios, debe haber un solo modelo de datos coherente o existe un medio para que un modelo / versión de datos se identifique.

¿Todavía estamos preguntando si podríamos usar las constantes de interfaz? De Verdad ?

Hay problemas de normalización de datos en juego más consecuentes que esta pregunta mundana. SI no resuelve esos problemas, la confusión que cree que causan las constantes de la interfaz es comparativamente nada. Nada.

A partir de la normalización del modelo de datos, usted determina los componentes como variables, como propiedades, como constantes de interfaz de contrato.

Luego, determina qué se aplica a la inyección de valor, la retención de la configuración de propiedad, las interfaces, las cadenas finales, etc.

Si tiene que usar la excusa de necesitar localizar un componente más fácil de dictar contra las constantes de la interfaz, significa que tiene la mala costumbre de no practicar la normalización del modelo de datos.

Quizás desee compilar el modelo de datos en una versión vcs. Que puede extraer una versión claramente identificable de un modelo de datos.

Los valores definidos en las interfaces están completamente garantizados para ser no mutables. Y compartible. ¿Por qué cargar un conjunto de cadenas finales en su clase desde otra clase cuando todo lo que necesita es ese conjunto de constantes?

Entonces, ¿por qué no esto para publicar un contrato de modelo de datos? Quiero decir, si puedes manejarlo y normalizarlo de manera coherente, ¿por qué no? ...

public interface CustomerService {
  public interface Label{
    char AssignmentCharacter = ':';
    public interface Address{
      String Street = "Street";
      String Unit= "Unit/Suite";
      String Municipal = "City";
      String County = "County";
      String Provincial = "State";
      String PostalCode = "Zip"
    }

    public interface Person {
      public interface NameParts{
        String Given = "First/Given name"
        String Auxiliary = "Middle initial"
        String Family = "Last name"
      }
    }
  }
}

Ahora puedo hacer referencia a las etiquetas contratadas de mis aplicaciones de una manera como

CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family

Esto confunde el contenido del archivo jar? Como programador de Java, no me importa la estructura del jar.

¿Esto presenta complejidad al intercambio de tiempo de ejecución motivado por osgi? Osgi es un medio extremadamente eficiente para permitir que los programadores continúen con sus malos hábitos. Hay mejores alternativas que osgi.

¿O por qué no esto? No hay fugas de las constantes privadas en el contrato publicado. Todas las constantes privadas deben agruparse en una interfaz privada llamada "Constantes", porque no quiero tener que buscar constantes y soy demasiado vago para escribir repetidamente "Cadena final privada".

public class PurchaseRequest {
  private interface Constants{
    String INTERESTINGName = "Interesting Name";
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

Quizás incluso esto:

public interface PurchaseOrderConstants {
  public interface Properties{
    default String InterestingName(){
       return something();
    }
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

El único problema con las constantes de la interfaz que vale la pena considerar es cuando se implementa la interfaz.

¿Esta no es la "intención original" de las interfaces? Como si me importara la "intención original" de los padres fundadores en la elaboración de la Constitución de los Estados Unidos, en lugar de cómo la Corte Suprema interpretaría las cartas escritas de la Constitución de los Estados Unidos.

Después de todo, vivo en la tierra de los libres, los salvajes y el hogar de los valientes. Sé valiente, sé libre, sé salvaje: utiliza la interfaz. Si mis compañeros programadores se niegan a usar medios de programación eficientes y perezosos, ¿estoy obligado por la regla de oro a disminuir mi eficiencia de programación para alinearme con la de ellos? Tal vez debería, pero esa no es una situación ideal.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.