¿Debería usar alguna vez variables miembro protegidas? ¿Cuáles son las ventajas y qué problemas puede causar esto?
¿Debería usar alguna vez variables miembro protegidas? ¿Cuáles son las ventajas y qué problemas puede causar esto?
Respuestas:
¿Debería usar alguna vez variables miembro protegidas?
Depende de lo quisquilloso que seas para esconderte.
Si aparece un desarrollador y subclasifica su clase, puede estropearlo porque no lo entiende completamente. Con los miembros privados, además de la interfaz pública, no pueden ver los detalles específicos de la implementación de cómo se están haciendo las cosas, lo que le brinda la flexibilidad de cambiarlo más tarde.
El sentimiento generalizado hoy en día es que provocan un acoplamiento indebido entre las clases derivadas y sus bases.
No tienen ninguna ventaja particular sobre los métodos / propiedades protegidos (alguna vez pudieron tener una ligera ventaja de rendimiento), y también se usaron más en una era en la que la herencia muy profunda estaba de moda, lo que no está de moda en este momento.
no particular advantage over protected methods/properties
ser no particular advantage over *private* methods/properties
?
super
construcción para llamar al constructor padre; luego se encargará de inicializar las variables de estado privadas en la clase principal.
Generalmente, si algo no se concibe deliberadamente como público, lo hago privado.
Si surge una situación en la que necesito acceso a esa variable privada o método de una clase derivada, lo cambio de privado a protegido.
Esto casi nunca sucede; realmente no soy un fanático de la herencia, ya que no es una forma particularmente buena de modelar la mayoría de las situaciones. De todos modos, continúa, no te preocupes.
Yo diría que esto está bien (y probablemente la mejor manera de hacerlo) para la mayoría de los desarrolladores.
El simple hecho del asunto es que , si algún otro desarrollador aparece un año después y decide que necesita acceso a su variable de miembro privada, simplemente editará el código, lo cambiará a protegido y continuará con su negocio.
Las únicas excepciones reales a esto son si está en el negocio de enviar archivos DLL binarios en forma de caja negra a terceros. Esto consiste básicamente en Microsoft, los proveedores de 'Custom DataGrid Control' y tal vez algunas otras aplicaciones grandes que se envían con bibliotecas de extensibilidad. A menos que esté en esa categoría, no vale la pena gastar tiempo / esfuerzo en preocuparse por este tipo de cosas.
El problema clave para mí es que una vez que crea una variable protegida, no puede permitir que ningún método de su clase dependa de que su valor esté dentro de un rango, porque una subclase siempre puede colocarlo fuera de rango.
Por ejemplo, si tengo una clase que define el ancho y el alto de un objeto renderizable, y protejo esas variables, no puedo hacer suposiciones sobre (por ejemplo), la relación de aspecto.
Críticamente, nunca puedo hacer esas suposiciones en ningún momento desde el momento en que el código se lanza como biblioteca, ya que incluso si actualizo mis configuradores para mantener la relación de aspecto, no tengo ninguna garantía de que las variables se establezcan a través de los configuradores o que se acceda a ellas a través del getters en código existente.
Tampoco puede ninguna subclase de mi clase optar por hacer esa garantía, ya que tampoco pueden hacer cumplir los valores de las variables, incluso si ese es el punto completo de su subclase .
Como ejemplo:
Al restringir las variables para que sean privadas, puedo aplicar el comportamiento que quiero a través de setters o getters.
En general, mantendría sus variables de miembro protegidas en el raro caso en el que también tenga control total sobre el código que las usa. Si está creando una API pública, diría que nunca. A continuación, nos referiremos a la variable miembro como una "propiedad" del objeto.
Esto es lo que su superclase no puede hacer después de hacer que una variable miembro esté protegida en lugar de privada con accesores:
Cree perezosamente un valor sobre la marcha cuando se lea la propiedad. Si agrega un método getter protegido, puede crear el valor de manera perezosa y devolverlo.
saber cuándo la propiedad ha sido modificada o eliminada. Esto puede introducir errores cuando la superclase hace suposiciones sobre el estado de esa variable. Hacer un método de establecimiento protegido para la variable mantiene ese control.
Establezca un punto de interrupción o agregue una salida de depuración cuando se lea o se escriba en la variable.
Cambie el nombre de esa variable miembro sin buscar en todo el código que podría usarla.
En general, creo que sería raro que recomiende crear una variable miembro protegida. Es mejor dedicar unos minutos a exponer la propiedad a través de captadores / definidores que horas después rastreando un error en algún otro código que modificó la variable protegida. No solo eso, sino que está asegurado contra la adición de funciones futuras (como la carga diferida) sin romper el código dependiente. Es más difícil hacerlo más tarde que hacerlo ahora.
A nivel de diseño, podría ser apropiado usar una propiedad protegida, pero para la implementación no veo ninguna ventaja en mapear esto a una variable miembro protegida en lugar de métodos de acceso / mutador.
Las variables miembro protegidas tienen desventajas significativas porque permiten de manera efectiva el acceso del código de cliente (la subclase) al estado interno de la clase base. Esto evita que la clase base mantenga efectivamente sus invariantes.
Por la misma razón, las variables de miembro protegidas también hacen que escribir código multiproceso seguro sea significativamente más difícil a menos que se garantice constante o se limite a un solo hilo.
Los métodos de acceso / mutador ofrecen considerablemente más estabilidad de API y flexibilidad de implementación bajo mantenimiento.
Además, si eres un purista de OO, los objetos colaboran / comunican enviando mensajes, no leyendo / configurando el estado.
A cambio ofrecen muy pocas ventajas. No los eliminaría necesariamente del código de otra persona, pero no los uso yo mismo.
La mayoría de las veces, es peligroso usar protected porque rompe un poco la encapsulación de su clase, que bien podría desglosarse por una clase derivada mal diseñada.
Pero tengo un buen ejemplo: digamos que puede algún tipo de contenedor genérico. Tiene una implementación interna y accesos internos. Pero debe ofrecer al menos 3 accesos públicos a sus datos: mapa, hash_map, similar a un vector. Entonces tienes algo como:
template <typename T, typename TContainer>
class Base
{
// etc.
protected
TContainer container ;
}
template <typename Key, typename T>
class DerivedMap : public Base<T, std::map<Key, T> > { /* etc. */ }
template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }
template <typename T>
class DerivedVector : public Base<T, std::vector<T> > { /* etc. */ }
Usé este tipo de código hace menos de un mes (por lo que el código es de la memoria). Después de pensarlo un poco, creo que si bien el contenedor Base genérico debería ser una clase abstracta, incluso si puede vivir bastante bien, porque usar Base directamente sería una molestia, debería estar prohibido.
Resumen Por lo tanto, ha protegido los datos utilizados por la clase derivada. Aún así, debemos tener en cuenta el hecho de que la clase Base debe ser abstracta.
protected
no está más encapsulado que public
. Estoy dispuesto a que me demuestren que estoy equivocado. Todo lo que tienes que hacer es escribir una clase con un miembro protegido y prohibirme modificarlo. Obviamente, la clase tiene que ser no final, ya que el objetivo de usar protected es la herencia. O algo está encapsulado o no lo está. No hay un estado intermedio.
En resumen, sí.
Las variables miembro protegidas permiten el acceso a la variable desde cualquier subclases así como desde cualquier clase en el mismo paquete. Esto puede resultar muy útil, especialmente para datos de solo lectura. Sin embargo, no creo que sean necesarios, porque cualquier uso de una variable miembro protegida se puede replicar utilizando una variable miembro privada y un par de getters y setters.
Para obtener información detallada sobre los modificadores de acceso .Net, vaya aquí
No hay ventajas o desventajas reales para las variables de miembro protegidas, es una cuestión de lo que necesita en su situación específica. En general, es una práctica aceptada declarar las variables miembro como privadas y habilitar el acceso externo a través de propiedades. Además, algunas herramientas (por ejemplo, algunos mapeadores O / R) esperan que los datos del objeto estén representados por propiedades y no reconocen las variables miembro públicas o protegidas. Pero si sabe que desea que sus subclases (y SOLO sus subclases) accedan a una determinada variable, no hay razón para no declararla protegida.