2010-08-19 20 views
14

Mi pregunta involucra específicamente Java, clases abstractas y el uso de datos protegidos. Me han dicho que todos los datos deben ser privados, y los getters/setters protegidos solo se usan.datos protegidos en la clase abstracta

Ahora, entiendo que queremos proteger los datos de la manipulación directa por usuarios ocasionales de la clase, y que los miembros de los datos públicos en general son una práctica cuestionable. He mirado en "campos de Java protegidas frente a captadores públicos" (Java protected fields vs public getters), pero todavía estoy dudoso que:

protected int i; 

es peor en una clase abstracta que:

private int i; 
protected int geti(); 
protected void seti(int j); 

Simplemente no estoy viendo el lado negativo cuando la clase abstracta está allí precisamente para proporcionar instalaciones de padres/comunes a las clases de los niños, y el alcance protegido está destinado a proporcionar acceso a los niños, al tiempo que protege los datos de los usuarios ocasionales. En la pregunta anterior mencioné que la mayoría de las respuestas parecen abordar el tema de por qué los datos en general deberían ser privados en lugar de públicos. Estoy tratando de enfocar mi pregunta específicamente en los datos existentes en un padre abstracto destinado a ser utilizado por los niños. El único comentario razonable que he escuchado hasta la fecha es que el uso de los datos protegidos de los padres (por ejemplo, int i arriba) te deja con el código en la clase secundaria que hace referencia a una variable no declarada en la clase secundaria. Menos convincente es el argumento (vea Common protected data member in base class?) de que puede querer cambiar el acceso algún día, y ahora debe respetar su interfaz. Esta es una clase abstracta, y está destinada a extenderse el 100% del tiempo.

Gracias! Título/Página # específicas referencias a libros son mucho más útiles que las referencias a "..any texto básico de programación Java ..."

=================== ======================= 10-13-2010
Esto era tanto una pregunta sobre clases abstractas como sobre datos protegidos. Me parece decepcionante que el foco haya cambiado en las respuestas a si el ocultamiento de datos es algo bueno en OOP (respuesta: sí). Aquí hay mucha profundidad que involucra la naturaleza de la clase abstracta, y cómo difiere de una clase regular no final, y qué posibles ventajas podría haber para fijar los nombres y tipos de elementos de datos en el padre abstracto para su uso por las clases de niños. Creo que existe la posibilidad de que la innovación y el mayor control se extiendan desde el padre abstracto a las clases de niños implementadores. Me preocupa que los principios generales, como las ventajas de ocultar datos, puedan convertirse en dogmas e inhibir la innovación y el desarrollo de nuevos patrones e ideas.

Gracias a todos los que contribuyeron.

+0

[Acabo de responder esto en otro lugar.] (Http://stackoverflow.com/questions/3525405/sometimes-i-dont-get-why-we-go-so-far-as-to-make-every- single-field-as-private-a/3525629 # 3525629) – cHao

+1

En realidad, Sr. Hao, usted respondió una pregunta diferente. La discusión general de lo público y lo privado no es lo que se cuestiona aquí, a menos que usted postule que la herencia es un tipo de interfaz. – cvsdave

Respuesta

11

Si el campo es privado y el acceso es a través de getters y setters, podrá volver a implementar getters y setters (por ejemplo, abandonar el campo y actualizar/leer el valor de una fuente externa) y así cambiar "campo" funciona sin tocar ninguna clase secundaria.

Si esto vale la pena, eso depende de usted.

+1

Este es el argumento # 2, el "menos convincente" declarado en la pregunta – cvsdave

+2

Bueno, además de algunos detalles menores de visibilidad del paquete mencionados en otras respuestas, creo que es el único argumento para hacer un campo privado con getters y setters protegidos. Personalmente, tampoco creo que sea muy convincente ... Los captadores y setters en Java son molestos. – alex

9

Considere los métodos protegidos como interfaz para las subclases, de la misma manera que los métodos públicos son una interfaz para todos los demás.

Proporcionar accesos permite a la clase base mantener su estado: no hay manera de que una subclase lo corrompa sin un truco intencional.

+2

La clase base, al ser abstracta, no puede tener ningún estado, ya que no se puede implementar. Supongo que esto es parte de mi razonamiento; los sdame ruloes no necesariamente se aplican a un padre abstracto como a un padre concreto. En este contexto, creo que introducir la idea de interfaz quizás distraiga la pregunta, aunque es un pensamiento interesante. Gracias por tu comentario. – cvsdave

+0

@cvsdave: La clase base obviamente * puede * tener estado, o no habría razón para hacer la pregunta sobre si y por qué (o por qué no) para exponerlo. Además, la clase base presumiblemente tiene métodos que dependen de ese campo y, por lo tanto, de su validez. (Si no lo hace, entonces el campo no pertenece en absoluto a la clase base, y solo se deben declarar getter y setter - abstract, por supuesto.) – cHao

1

Si no necesita que su hijo directamente acceda a él, ¿por qué los dejaría?

No es un inconveniente para el uso protegido. Pero si no es necesario, tal vez sea mejor evitarlo y controlar el acceso en sus campos.

0

Si alguien subclasifica su clase y coloca la subclase en el mismo paquete que su clase actual, es posible que desee sobrescribir sus getters y setters. Por ejemplo, quieren asegurarse de que i solo se pueda establecer en un valor mayor que 1.

Aparte de eso, depende de usted. La convención es que hay getters y setters para todo.

+0

Este es el argumento # 2, el "menos convincente" declarado en la pregunta. – cvsdave

+0

Hmmm, no veo cómo eché de menos que estaba allí. ¿Eso fue editado después? – Serplat

1

En Java los miembros protegidos son accesibles para todos los miembros en el mismo paquete, además de las clases que se extienden. Hacer que el campo sea privado evitará que las clases en el mismo paquete accedan directamente a él.

También está el punto que Alex planteó anteriormente.

0

Ocultar información es valioso, incluso entre clases relacionadas por herencia.

Además de permitir la re-aplicación, como se ha señalado anteriormente por Alex:

  • Puede establecer puntos de interrupción en los métodos.
  • Puede agregar restricciones en un solo lugar.
3

Tener menos acceso no es un inconveniente, es una ventaja. Las clases siempre deben limitar el acceso a la mayor parte de su estado interno como sea posible. No piense por qué los elementos internos deben ocultarse, en lugar de pensar por qué deberían estar expuestos. En este caso, como en todos los casos, a menos que exista una buena razón para exponer la variable, entonces no la exponga.

+1

¿Cómo se aplica esto al problema específico relacionado con las clases abstractas y está protegido? "... por qué deberían estar expuestos ..." esta es exactamente la razón por la cual el setter/getter está escrito en el caso alternativo. Si no se necesitara acceso, ¡la pregunta no se aplicaría! – cvsdave

+1

No exponga el campo como protegido. Hazlo privado y usa un captador y/o colocador si es necesario. Esto limita el acceso tanto como sea posible, lo que siempre es bueno. –

0

Desea utilizar getters/setters porque el uso de protected int i; permite anular el campo (lo que desea evitar a toda costa).

Desea rechazar la sobrescritura del campo porque funciona de forma diferente a la sobrescritura del método. La anulación de campo no hace que el campo anulado sea inaccesible (el tipo de referencia determina con qué instancia del campo está trabajando).

Los campos accesibles deben ser finales o en una clase final.

public class OverridingFun { 
    public static class Base { 
     public int i = 1; 
     public int getI(){ return i; } 
    } 
    public static class A extends Base { 
     public int i = 2; 
     public int getI(){ return i; } 
    } 
    public static class B extends A { 
     public int i = 3; 
     public int getI(){ return i; } 
    } 
    public static void main(String [] args){ 
     B b = new B(); 
     A bAsA = b; 
     Base bAsBase = b; 

     System.out.println(b.getI());//3 
     System.out.println(bAsA.getI());//3 
     System.out.println(bAsBase.getI());//3 

     System.out.println(b.i);//3 
     System.out.println(bAsA.i);//2 
     System.out.println(bAsBase.i);//1 

     b.i = 4; 
     bAsA.i = 5; 
     bAsBase.i = 6; 

     System.out.println(b.i);//4 
     System.out.println(bAsA.i);//5 
     System.out.println(bAsBase.i);//6 
    } 
} 

A primera vista, esto parece algo que simplemente haría que el código sea difícil de leer, pero tiene implicaciones en la funcionalidad. Supongamos que el campo queda anulado por una clase derivada, ya que los setters no se utilizan, no hay forma de actualizar automágicamente el campo base y no hay manera de detectar si alguien ha cambiado el campo base (ya que el valor base todavía es accesible) y actualizar el campo derivado. Es fácil imaginar que la base y los estados derivados podrían desincronizarse y que los errores serían difíciles de rastrear. En pocas palabras, es una API muy frágil.

Lamentablemente, no hay forma de evitar esto, ya que la palabra clave final, que protege contra anulación, también hace campos de escritura una sola vez. Entonces no hay campos editables que no se puedan cargar.

Personalmente, estoy bastante sorprendido de que los diseñadores de idiomas permitieran sobreescribir el campo en absoluto. La ventaja de utilizar setters es que cada nivel puede garantizar la integridad de su propio estado y la confianza de que las clases derivadas no lo han ensuciado. La anulación de campo es solo pedir problemas.

Cuestiones relacionadas