2010-01-09 10 views
5

Leí "Effective Java" de Joshua Bloch y eliminé el 'Constant Interface anti-pattern' de nuestra aplicación. El truco consiste en utilizar una clase de utilidad no instanciable cuyo constructor es privado y definir todas las constantes como 'pública estática final'Extendiendo clase no instanciable en java

Tengo que extender esta clase de utilidad constante. Solo puedo hacer esto cuando cambio el constructor a protected.

Podría alguien sugerir una mejor manera.

public class Constants { 
    private Constants() {} // Prevent instantiation 
    public static final String MyString = "MyString"; 
} 

public class MyConstants extends Constants { 
    private MyConstants() {} // Compiler error : Implicit super constructor Constants() is not visible. 
    public static final String MySecondString = "MySecondString"; 
} 
+3

¿Por qué * tiene que * extender la clase que contiene constantes? ¿Ganas mucho de eso (en lugar de simplemente tener clases separadas que no se extienden entre sí)? – Jonik

+0

Estoy de acuerdo. Gracias – Nayn

Respuesta

7

Normalmente no se supone que amplíe estas clases constantes. ¿Podría darnos un ejemplo más concreto de lo que está tratando de hacer?

Normalmente, desea agrupar las constantes cuando están relacionadas, por ejemplo, las constantes matemáticas o los nombres de los parámetros de configuración para un componente funcional en particular.

Si las constantes están realmente relacionadas, ¿hay alguna forma de que simplemente las pueda agregar a la clase original? Alternativamente, ¿hay alguna razón por la que no pueda crear una clase separada para sus constantes?

+1

Exactamente. Incluso creo que no necesitamos extender las clases de constantes. El código es heredado y arreglaría esto. Muchas gracias. – Nayn

2

No veo nada de malo en cambiar el constructor a protegido.

Tampoco veo nada de malo con el uso de interfaces para mantener constantes.

+4

"Cuando una clase implementa una interfaz, se convierte en parte de la API pública de la clase. Los detalles de implementación no deben filtrarse a las API públicas". http://java.sun.com/j2se/1.5.0/docs/guide/language/static-import.html. ver el Artículo 17 efectivo de Java para más detalles :) –

+1

Puedo entender el sentimiento, pero creo que mucha gente se está haciendo un nudo tratando de encontrar el mejor compromiso posible para los requisitos posiblemente conflictivos, mientras que otros siguen adelante y hacen las cosas. La cultura del lenguaje Java ha logrado encerrarse en una red confusa de patrones, convenciones y restricciones que, al final, no estoy seguro de que contribuyan a una mayor productividad. Pero esto es, por supuesto, solo una opinión personal mía. –

+4

Lo que creo que es menos controvertido es que las "reglas" como las de * Effective Java * son mucho más relevantes para las bibliotecas de uso público y los kits de herramientas que para los proyectos internos de un solo uso. Es muy importante para Sun, Apache y otros proyectos altamente visibles poner el listón alto. Mi opinión es que diferentes contextos pueden justificar la relajación un poco. –

1

¿Hay algún problema con el uso de la palabra clave protected? Me parece una solución pragmática.

Tengo que decir (además) que no tengo un problema particular con el uso de una interfaz para mantener las constantes. Use static import para que estén disponibles en sus clases de clientes. Aunque no recomendaría implementarlo.

+0

No lo implementaría necesariamente *, aunque ... –

+0

"Para poder evitar esto, la gente a veces pone miembros estáticos en una interfaz y heredan de esa interfaz. Esta es una mala idea. De hecho, es una mala idea que haya un nombre para ella: la Constant Interface Antipattern (ver el Artículo Efectivo de Java 17). El problema es que una clase el uso de los miembros estáticos de otra clase es un mero detalle de implementación. Cuando una clase implementa una interfaz, se convierte en parte de la API pública de la clase. Los detalles de implementación no deben filtrarse a las API públicas ". http://java.sun.com/j2se/1.5.0/docs/guide/language/static-import.html –

+0

@Brian No puedes evitarlo, ese es el problema. Y no puedes culpar a alguien por no usar tu API correctamente (la API es defectuosa, no el usuario de la API). –

1

Si las clases están en el mismo paquete y le quieren prohibir la herencia de clases no de paquetes, considere el uso de acceso predeterminado:

public class Constants { 
    Constants() {} // Prevent instantiation 
    public static final String MyString = "MyString"; 
} 
3

que suelo hacer lo siguiente:

public abstract class Constants { 
    // ...constants... 
    public Constants() { 
     throw new UnsupportedOperationException(); // prevent instantiation 
    } 
} 

Este forma en que la clase se puede extender para crear una clase de utilidad derivada, pero cualquier intento (erróneo) de instanciarlo fallará. Deseo que java.util.Collections se haya definido de esa manera, por lo que no habría que definir una Collections2 (o similar) para métodos de utilidad adicionales.

BTW, dada una clase abstracta, "protegido" y "público" significa efectivamente lo mismo para los constructores. No hay prácticamente ningún beneficio en sólo hacer un constructor protegido, como cualquier persona todavía puede crear fácilmente una instancia de la clase a pesar de la "protección":

public class Base { 
    protected Base() { } 
} 

// Somewhere else: 
Base b = new Base() { }; // anonymous subclass 
0

uso el enfoque de Joshua Bloch recomienda.

public class Constants { 

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

    public static class Math { 

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

     public static final int COUNT = 12; 
    } 

    public static class Strings { 

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

     public static final String LOREM = "Lorem"; 
    } 

} 

La clase Constants y las clases anidadas

  • no puede extenderse
  • no puede ser instanciada

Si necesitaba constantes de grupos por tipo, lo haría solo usa clases anidadas. Recuerde que cada clase anidada debe arrojar un AssertionError.

+1

Gran parte del ruido de ese código podría eliminarse mediante el uso de enumeraciones. – Kevin

Cuestiones relacionadas