Entiendo la idea del alcance del paquete y, a veces, incluso pensé que lo quería. Sin embargo, cada vez que me establezco con la intención seria de intentar usarlo, descubro que no se ajusta a las necesidades que pensé que serviría.
Mi problema principal siempre parece ser que las cosas que deseo limitar el alcance nunca están en el mismo paquete. Conceptualmente, todos pueden estar vinculados, pero la división lógica de los datos dentro de la aplicación los tiene como paquetes secundarios separados de un paquete más grande.
Por ejemplo, puedo tener un modelo Mission y solo quiero que otras herramientas de Mission, como mis MissionServices, utilicen algunos métodos. Sin embargo, termino con Missions.models y Missions.services como mis paquetes, por lo que MissionModel y MissionService no son el mismo alcance de paquete. Nunca parece que haya una situación en la que los paquetes contengan adecuadamente las cosas que me gustaría tener permisos elevados sin incluir también muchas cosas que no deseo tener esos permisos; y rara vez siento que la ventaja del alcance de un paquete justifica la modificación de la arquitectura de mi proyecto para colocar todo en el mismo paquete. A menudo, Aspectos o algún tipo de inversión de control resultan ser el mejor enfoque para cualquier problema que considere brevemente el alcance del paquete.
Tengo curiosidad por decir que esto generalmente se considera cierto en todos los desarrolladores de Java, o es solo una casualidad del trabajo que hago. ¿Se utiliza mucho el alcance del paquete en el mundo real? ¿Hay muchos casos en los que se considera una buena forma de usar, o se ve principalmente como un comportamiento heredado que rara vez se explota en el desarrollo moderno?
No estoy preguntando nada acerca de por qué el ámbito privado del paquete es predeterminado, estoy preguntando cuándo se debe usar independientemente de los valores predeterminados. La mayoría de las discusiones sobre por qué es predeterminado no entran realmente en cuenta cuando el alcance del paquete es realmente útil, sino que simplemente argumentan por qué los otros dos ámbitos comúnmente utilizados no deberían ser predeterminados para que el paquete gane por proceso de eliminación. Además, mi pregunta es sobre el estado actual de desarrollo. Específicamente, nos hemos desarrollado hasta el punto en que otras herramientas y paradigmas hacen que el alcance del paquete sea menos útil que cuando la decisión de hacerlo predeterminado tenía sentido.
java.util.String
yjava.util.Integer
.Respuestas:
En todo el
java.util.*
paquete hay instancias en las que el código se escribe con protección a nivel de paquete. Por ejemplo, este bit dejava.util.String
- un constructor en Java 6 :o este método getChars :
La razón de esto es que los diseñadores del código (y
java.util.*
se puede considerar como una biblioteca bastante grande) querían la capacidad de tener un rendimiento más rápido a costa de la pérdida de varias medidas de seguridad (comprobaciones de rango en matrices, acceso directo a otros campos) que implican la implementación en lugar de la interfaz, el acceso 'inseguro' a partes de la clase que de otro modo se consideran inmutables a través de métodos públicos).Al restringir el acceso a estos métodos y campos solo por otras clases en el
java.util
paquete, se logra un acoplamiento más estrecho entre ellos, pero también se evita exponer estos detalles de implementación al mundo.Si está trabajando en una aplicación y no necesita preocuparse por otros usuarios, la protección a nivel de paquete no es algo de lo que deba preocuparse. Aparte de varios aspectos de la pureza del diseño, podría hacer todo
public
y estar de acuerdo con eso.Sin embargo, si está trabajando en una biblioteca que será utilizada por otros (o desea evitar enredar demasiado sus clases para una refactorización posterior), debe usar el nivel de protección más estricto que se le brinde para sus necesidades. A menudo esto significa
private
. A veces, sin embargo, debe exponer un poco de los detalles de implementación a otras clases en el mismo paquete para evitar repetirse o facilitar un poco la implementación real a expensas del acoplamiento de las dos clases y sus implementaciones. Por lo tanto, el nivel de protección del paquete.fuente
Integer.toString()
yString.valueOf(int)
puede compartirlo sin exponerlo al mundo. Lasjava.util
clases deben trabajar en concierto para proporcionar un conjunto más amplio de funcionalidad en lugar de ser clases individuales que son completamente islas en sí mismas: están juntas en un paquete y comparten la funcionalidad de implementación a través del alcance a nivel de paquete.En algún momento, escalo la visibilidad de los métodos privados o protegidos para empaquetar para permitir que una prueba junit acceda a algunos detalles de implementación a los que no se debe acceder desde el exterior.
dado que junit-test tiene el mismo paquete que item-under-test, puede acceder a estos detalles de implementación
ejemplo
Es discutible si este es un "buen" uso o no, pero es pragmático
fuente
protected
al alcance del paquete?protected
Ya suministra acceso a paquetes. Es un poco extraño, pero creo que no querían exigir declaraciones de alcance compuesto comoprotected packagescope void doSomething()
(que también requiere una nueva palabra clave).No es tan útil, especialmente por defecto, en un mundo donde las personas tienden a usar los nombres punteados de los paquetes como si fueran subpaquetes. Debido a que Java no tiene un subpaquete, entonces xyinternals no tiene más acceso a xy que a ab Los nombres de paquete son iguales o diferentes, una coincidencia parcial no es diferente de no tener nada en común.
Supongo que los desarrolladores originales nunca esperaron que se usara esa convención, y quisieron mantener las cosas simples sin agregar la complejidad de los paquetes jerárquicos de estilo Ada.
Java 9 está abordando esto, ya que puede colocar varios paquetes en un módulo y solo exportar algunos. Pero eso hará que el alcance del paquete sea aún más redundante.
En un mundo ideal, cambiarían el alcance predeterminado a 'alcance del módulo, si existe un módulo contenedor, de lo contrario, alcance del paquete'. Luego puede usarlo para compartir la implementación dentro de un módulo, lo que permite refactorizar sin romper las interfaces exportadas. Pero tal vez haya alguna sutileza por la que eso rompería la compatibilidad con versiones anteriores o sería malo.
fuente
El tipo de cohesión que describe no es realmente el mejor ejemplo de dónde usaría el acceso a paquetes. El paquete es útil para crear componentes, módulos que son intercambiables en una interfaz.
Aquí hay un ejemplo aproximado de un escenario. Supongamos que su código se reorganizó para estar más relacionado con la cohesión funcional y la componente. Quizás 3 frascos como:
Al usar el nivel de paquete en el Mission5000.java, puede estar seguro de que ningún otro paquete o componente como el MissionManager puede ajustarse estrechamente a la implementación de la misión. Ese es solo el componente provisto por "terceros" de "M co" en realidad crea su propia implementación especial de marca de una Misión. El administrador de la misión debe llamar a MissionBuiler.createMission (...) y usar la interfaz definida.
De esta manera, si se reemplaza el componente de implementación de Mission, sabemos que los implementadores de MissionManager.jar no omitieron la API y usaron la implementación de MCo directamente.
Por lo tanto, podemos intercambiar MCo-missionizer5000.jar con un producto de la competencia. (O tal vez un Simulacro para la unidad que prueba al Gerente de la Misión)
Por el contrario, MCo puede esconder sus secretos comerciales de misioneros patentados.
(Esto también está relacionado con la aplicación de ideas de inestabilidad y abstracción en los componentes).
fuente
Debido a que el alcance del paquete en Java no está diseñado de forma jerárquica, no es útil. No usamos el alcance del paquete en absoluto y definimos todas las clases como públicas.
En su lugar, utilizamos nuestras propias reglas de acceso basadas en la jerarquía de paquetes y los nombres de paquetes predefinidos.
Si está interesado en los detalles de google para "CODERU-Rules".
fuente