¿Por qué un constructor debería ser una clase interna en lugar de estar en su propio archivo de clase?

24

Muchos Builder Patternejemplos hacen de la Builderclase interna del objeto que construye.

Esto tiene algún sentido ya que indica lo que Buildercompila. Sin embargo, en un lenguaje tipado estáticamente sabemos qué Buildercompila.

Por otro lado, si se Buildertrata de una clase interna, debe saber en qué clase se Buildercompila sin mirar dentro de la clase Builder.

Además, tener el constructor como una clase interna reduce el número de importaciones, ya que puede ser referenciado por la clase externa, si eso le importa.

Y luego hay ejemplos prácticos donde el Builderestá en el mismo paquete, pero no una clase interna, como StringBuilder. Usted sabe que Builder debería construir un Stringporque se llama así.

Dicho esto, la única buena razón por la que puedo pensar para hacer una Builderclase interna es que sabes cuál es la clase Buildersin saber su nombre o sin depender de las convenciones de nombres. Por ejemplo, si StringBuilderfuera una clase interna de String, probablemente habría sabido que existía antes que yo (especulativo).

¿Hay alguna otra razón para hacer de la Builderclase interna o simplemente se reduce a preferencias y rituales?

Nathanial
fuente

Respuestas:

30

Creo que la razón para hacerlo es para que la clase interna (el Constructor) pueda acceder a los miembros privados de la clase que está creando.

De http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Las clases anidadas no estáticas (clases internas) tienen acceso a otros miembros de la clase adjunta, incluso si se declaran privadas.

...

Considere dos clases de nivel superior, A y B, donde B necesita acceso a los miembros de A que de otro modo se declararían privados. Al ocultar la clase B dentro de la clase A, los miembros de A pueden declararse privados y B puede acceder a ellos.

...

Al igual que con los métodos y las variables de instancia, una clase interna está asociada con una instancia de su clase adjunta y tiene acceso directo a los métodos y campos de ese objeto.

Aquí hay un código para tratar de ilustrar esto:

class Example {

    private int x;

    public int getX() { return this.x; }

    public static class Builder {

        public Example Create() {
            Example instance = new Example();
            instance.x = 5; // Builder can access Example's private member variable
            return instance;
        }
    }
}

Como clase estática, Builder no tiene una instancia específica de Example a la que esté vinculada. Sin embargo, dada una instancia de Example (o una que crea), Builder puede acceder a los miembros privados de esa instancia.

Aprendiz del Dr. Wily
fuente
Gran respuesta, eso tiene sentido! Sin embargo, los patrones de constructor generalmente tienen una clase interna estática y solo podrían acceder a miembros privados estáticos de la clase externa. Si tuvieras un constructor para una clase instanciada, eso sería muy raro.
Nathanial
1
@Nathanial en absoluto, las variables de instancia privada también son accesibles: ideone.com/7DyjDR
amon
1
@nathanial: Sí, pero el constructor no está manipulando la clase; está manipulando un objeto de la clase que el propio constructor ha instanciado.
Robert Harvey
@amon Veo lo que hiciste allí. ¡Gracias por la explicación!
Nathanial
Específicamente, le da al constructor acceso a un constructor privado para la clase que se está construyendo, permitiendo que esa clase sea inmutable (todos los campos finales) y solo instanciable a través del constructor.
Matthew McPeak
1

No hay "debería" en este caso. Definir un generador dentro de otra clase o tenerlo separado es ortogonal al patrón del generador. Muchos ejemplos hacen esto debido a la conveniencia de presentar el código en un archivo consistente (también para acceder a miembros privados, pero eso también depende del contexto). Siéntase libre de hacer lo contrario

AZ01
fuente
No estoy seguro de por qué esta respuesta fue rechazada, por cualquier otro motivo que no sea "porque no es así como lo hacemos en Java". El Patrón de constructor proporciona un contenedor alrededor de un constructor que toma varios parámetros. Si el constructor toma esos parámetros, no es necesario que el objeto Builder acceda a miembros privados.
Greg Burghardt