buscando un caso de uso específico en el que tanto una subclase como una clase dentro del mismo paquete necesiten acceder a un campo o método protegido ...
Bueno, para mí, este caso de uso es más general que específico, y se deriva de mis preferencias para:
- Comience con un modificador de acceso lo más estricto posible, recurriendo a uno o más débiles solo más tarde, según se considere necesario.
- Haga que las pruebas unitarias residan en el mismo paquete que el código probado.
Desde arriba, puedo comenzar a diseñar mis objetos con modificadores de acceso predeterminados (comenzaría con, private
pero eso complicaría las pruebas unitarias):
public class Example {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
void doSomething() {} // default access
}
static class Unit2 {
void doSomething() {} // default access
}
static class UnitTest {
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Nota al margen en el fragmento anterior Unit1
, Unit2
y UnitTest
están anidados dentro Example
para simplificar la presentación, pero en un proyecto real, probablemente tendría estas clases en archivos separados (e UnitTest
incluso en un directorio separado ).
Luego, cuando surja una necesidad, debilitaría el control de acceso de forma predeterminada a protected
:
public class ExampleEvolved {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
protected void doSomething() {} // made protected
}
static class Unit2 {
protected void doSomething() {} // made protected
}
static class UnitTest {
// ---> no changes needed although UnitTest doesn't subclass
// ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Verá, puedo mantener el código de prueba de la unidad ExampleEvolved
sin cambios debido a que los métodos protegidos son accesibles desde el mismo paquete, a pesar de que acceder al objeto no es una subclase .
Se necesitan menos cambios => modificación más segura; después de todo, cambié solo los modificadores de acceso y no modifiqué qué métodos Unit1.doSomething()
y Unit2.doSomething()
qué hago, por lo que es natural esperar que el código de prueba de la unidad continúe ejecutándose sin modificaciones.
protected
es solo una subclase? Honestamente, durante mucho tiempo, tuve la impresión de que ese era el comportamientoprotected
es solo de clase y subclase, yinternal
es de toda la biblioteca / paquete. También tieneprotected internal
cuál es el equivalente a Javaprotected
.En mi humilde opinión, esta fue una mala decisión de diseño en Java.
Solo especulando, pero creo que querían que los niveles de acceso estuvieran en una progresión estricta: privado - "paquete" - protegido - público. No querían tener una jerarquía, donde algunos campos estarían disponibles para el paquete pero no las subclases, algunos disponibles para las subclases pero no el paquete, y algunos ambos.
Aún así, en mi humilde opinión, deberían haber ido para otro lado: Dijo que protegido es visible solo para la clase y las subclases, y que el paquete es visible para la clase, las subclases y el paquete.
A menudo tengo datos en una clase que deben ser accesibles para las subclases, pero no para el resto del paquete. Me cuesta pensar en un caso en el que lo contrario sea cierto. He tenido algunas raras ocasiones en las que he tenido un conjunto de clases interrelacionadas que necesitan compartir datos pero que deberían mantener esos datos seguros fuera del paquete. Así que está bien, póngalos en un paquete, etc. Pero nunca he tenido un caso en el que quiera que el paquete comparta datos, pero quiero mantenerlo fuera de las subclases. De acuerdo, me puedo imaginar la situación que se avecina. Supongo que si este paquete es parte de una biblioteca que podría extenderse por clases de las que no sé nada, por las mismas razones que haría que los datos de una clase fueran privados. Pero es mucho más común querer que los datos estén disponibles solo para la clase y sus hijos.
Hay muchas cosas que mantengo en privado entre mis hijos y yo y que no compartimos con los vecinos. Es muy poco lo que mantengo en privado entre mí y los vecinos y no comparto con mis hijos. :-)
fuente
Un buen ejemplo que viene a la mente de inmediato son las clases de utilidad que se usan mucho en el paquete pero que no desea acceso público (detrás de escena, carga de imágenes desde el disco, clases de creación / destrucción de identificadores, etc. .) en lugar de hacer que todo [el equivalente de Java
friend access modifier or idiom
enC++
] de todas las demás clases esté automáticamente disponible.fuente
Los casos de uso para el modificador de acceso protegido / paquete son similares a los de los modificadores de acceso amigo en C ++.
Un caso de uso es cuando se implementa el patrón Memento .
El objeto de recuerdo necesita acceder al estado interno de un objeto, retenerlo, para servir como punto de control para operaciones de deshacer.
Declarar la clase en el mismo paquete es una de las formas posibles de lograr el patrón Memento, ya que Java no tiene un modificador de acceso "amigo" .
fuente
¿simetría?
Es raro necesitar dicho acceso, por lo que el acceso predeterminado rara vez se usa. Pero a veces los marcos lo quieren para el código generado, donde las clases de contenedor se colocan en el mismo paquete que interactúa directamente con sus clases, yendo a los miembros en lugar de a los accesores por razones de rendimiento. Piense en GWT.
fuente
La jerarquía de encapsulación de Java está bien definida:
Clase -> Paquete -> Herencia
"Protegido" es solo una forma más débil de privacidad que el paquete predeterminado, según lo decidido por los diseñadores de Java. El acceso a los elementos predeterminados del paquete está restringido a un subconjunto de las entidades que pueden acceder a los elementos protegidos.
Tiene mucho sentido desde un punto de vista matemático y de implementación tener sus conjuntos de entidades que tienen acceso a cosas para anidar. (No puede anidar su conjunto de acceso a paquetes dentro de su conjunto de acceso protegido porque las clases pueden heredar de otros paquetes).
Tiene sentido desde un punto de vista conceptual tener algo en java.util para ser "más amigable" con otra clase en el paquete que algo en com.example.foo.bar que lo está subclasificando. En el primer caso, es probable que las clases sean escritas por el mismo autor, o al menos codificadores de la misma organización.
fuente