2011-03-22 5 views
35

me he dado cuenta lo siguiente patrón de código mientras se navega a través de algunas fuentes de bibliotecas 3 ª parte de mi proyecto:¿Cuál es la ventaja de tener clases internas estáticas públicas de una interfaz/clase?

public interface MyInterface { 
    public static class MyClass1 implements MyInterface { ... } 
    public static class MyClass2 implements MyInterface { ... } 
    public static class MyClass3 implements MyInterface { ... } 
} 

O esta otra:

public class MyBaseClass { 
    public static class MyClass1 extends MyBaseClass { ... } 
    public static class MyClass2 extends MyBaseClass { ... } 
    public static class MyClass3 extends MyBaseClass { ... } 
} 

ejemplos de la vida real:

  • SwingX: org.jdesktop.swingx.decorator.HighlightPredicate (Source)
  • Sustancia: org.pushingpixels.substance.api.renderers.SubstanceDefaultTableCellRenderer (Source)

¿Cuál es la ventaja de tener una estructura de código como esta?

Mi primer pensamiento fue "agregación", pero lo mismo podría lograrse utilizando paquetes antiguos. Entonces, ¿cuándo/por qué es mejor utilizar clases internas públicas en lugar de un paquete?

+0

Yo no miro a los ejemplos de la vida real que ha publicado , pero una diferencia es que las clases internas pueden usar miembros privados de la clase externa, que no es el caso si fueran 'hermanos' (clases separadas de nivel superior) –

+0

Buena pregunta. Personalmente, recomendaría evitar este patrón, ya que oculta las clases públicas en un lugar que, por lo general, la gente no espera encontrar, sin proporcionar ningún beneficio obvio para la compensación. Pero tal vez alguien más sepa cuál es el beneficio de este patrón. – aroth

+0

@Grzegorz, las interfaces no pueden tener miembros privados. –

Respuesta

17

Creo que esto se basa en la agregación, quizás tampoco valen la pena para crear una clase de nivel superior. A veces hago esto si algo es demasiado pequeño para crear un paquete (para separarlos de los demás), pero las clases correspondientes solo deben usarse dentro del contexto de la clase de nivel superior. En mi opinión, esta es una decisión de diseño.

El patrón de decorador puede ser un buen ejemplo, se pueden aplicar en la clase de nivel superior pero son tan simples que no valen la pena para ser también de alto nivel. Puede mostrar fácilmente la propiedad utilizándolas como clases internas.

Eso no es tan visible a primera vista con los paquetes. Usted ve directamente la clase/interfaz dependiente.

Además, es posible acceder a los campos privados de una clase, esto podría ser útil y es más refinado que el alcance privado del paquete.

10

Un uso que se me ocurre es proporcionar implementaciones ya hechas de la interfaz, públicamente disponibles para cualquier persona, pero aún atadas conceptualmente a la interfaz madre.

Esto tiene sentido solo si la interfaz es simple (por lo tanto, las clases de implementación interna son pequeñas), no hay demasiadas, y la mayoría de los clientes de interfaz realmente las necesitan. De lo contrario, complican el archivo fuente, lo que dificulta su comprensión.

1

Una interfaz interna tiene que ser estática para poder acceder a ella. La interfaz no está asociada con instancias de la clase, sino con la clase misma, por lo que se accederá con Foo.Bar, como tal.

4

En cuanto a las clases y sus clases internas (no se aplica a las interfaces) una diferencia es que las clases internas pueden usar miembros privados de la clase externa, que no es el caso si fueran hermanos '(clases separadas de nivel superior).

Ejemplo:

public class MyBaseClass { 

    private static String staticField = "outer"; 

    public static class MyClass1 extends MyBaseClass { 

     public MyClass1() { 
      MyBaseClass.staticField = "inner1"; 
     } 

    } 
} 

Esto no funcionará si se ha movido el MyClass de la clase externa.

0

Creo que el motivo de la clase interna estática pública es una herramienta o utilidad adicional para la clase "base".

0

Cuando le pregunté a mi profesor sobre esto hace muchos años, respondió que de esta manera puede exponer una interfaz totalmente diferente para el mismo objeto. Suponga que tiene

public class MyBaseClass { 
    public static class MyClass1 { 
     public int myClassMethod1() {...} 
     public int myClassMethod2() {...} 
    } 
    ... 
    public void myBaseMethod1() {...} 
    public void myBaseMethod2() {...} 
} 

Debido a instancias de MyClass1 tienen acceso a las partes internas de MyBaseClass, puede exponer el mismo comportamiento interno como una instancia de MyClass1 o como una instancia de MyBaseClass medida que sea necesario, incluso si los métodos definidos en ambas clases son totalmente diferentes.

Nunca tuve que usar eso, pero es realmente interesante.

1

Hacerlo de esta manera se puede ahorrar algo archivos de código fuente extra y hace que sea posible dar a la clase un buen nombre jerárquico, es decir, en lugar de org.foo.bar.XY.Defaultorg.foo.bar.DefaultXY

Cuestiones relacionadas