2011-01-21 12 views
8

¿Es realmente imposible ocultar algunas clases en un archivo jar?Ocultar clases en un archivo jar

No quería permitir la creación de instancias directas de las clases para que sea más flexible. Solo la fábrica (o una fachada) debe ser visible de este frasco.

¿Hay alguna otra manera que resolver este problema que crear dos proyectos? (dos proyectos: el primero contiene las clases (aplicación) y el otro referencias a la primera y contiene la fábrica, y más tarde sólo se le haga referencia el segundo)

+1

No estoy seguro de lo que quiere decir con "ocultarse". Los archivos jar son solo archivos .zip, por lo que cualquier persona puede abrirlos y ver sus archivos de clase dentro de ellos. – jonescb

+0

Solo quiero evitar que las clases se puedan usar afuera (por accidente) para crear instancias. – nrainer

+1

Creo que debes confiar en el usuario de tus clases y proporcionar suficiente documentación decente sobre qué usar y qué no. De todos modos, no hay manera de que puedas evitar todos los errores que los desarrolladores que usan tus jarras pueden generar. Una alternativa, por supuesto, es hacer tus propios constructores tan complejos que nadie pueda entenderlos y recurrirá naturalmente a las clases de fábrica: D –

Respuesta

3

Creo que tendrá un fallo del compilador o una advertencia si su método de fábrica pública intenta devolver algo que está "oculto".

No, no puede ocultar una clase pública sin volver a implementar su propio ClassLoader o usar OSGi o algo similar.

Lo que puede hacer es separar la API de interfaz de la implementación, p. tener un proyecto que contiene solo las interfaces y otro poryecto que contiene las implicaciones. Sin embargo, aún no puede ocultar las clases de implementación.

+0

Eso es lo que quise decir al crear dos proyectos. Creo que lo haré incluso si aumenta la cantidad de proyectos. – nrainer

2

Obfuscation pueden ayudarle a alguna manera.

+0

Seconded, aunque no lo oculta. –

+0

@Elijah * de alguna manera * –

+0

Por lo tanto, 'secundó' y +1 –

2

Con cargadores de clase estándar, archivos jar simples y antiguos esto no es posible. OSGi cas este concepto de hacer visible a otro paquete solo algunos paquetes y no otros (es decir, la separación de la API pública y la implementación interna).

Si está usinf eclipsar puede hacer cumplir dichas normas con this

5

estoy entender que no está buscando para ocultar las clases reales, simplemente evitar que su construcción fuera de una clase de fábrica. Esto creo que se puede lograr fácilmente usando la visibilidad privada (predeterminada) del paquete en los constructores de la clase. La única limitación es que tendrá que tener las clases y la fábrica en el mismo paquete, de modo que en una base de código mediana a grande las cosas se vuelvan innecesariamente complejas.

+4

Oh, de hecho, de esta forma, cualquiera puede llamar a sus constructores creando sus propias clases de fábrica y colocándolas en el mismo paquete ... ¿Tal vez sería mejor comenzar con _por qué_ quieres ocultar estas cosas? –

+1

Lo tienes. Pero la limitación es exactamente el problema. Hay muchas clases y realmente no quiero poner todo en un solo paquete. – nrainer

+1

@ Mikko: A su comentario: Eso podría resolverse sellando el paquete. – nrainer

3

Si entiendo su pregunta correctamente, le gustaría asegurarse de que los usuarios de su biblioteca se vean obligados a utilizar su fábrica para instanciar sus objetos en lugar de utilizar los propios constructores.

Como yo lo veo, hay dos posibilidades, una de las cuales es tonta pero utilizable en pocos casos específicos, y la otra es la forma más práctica y probablemente más comúnmente utilizada de hacerlo.

  1. Usted puede hacer todas sus clases en private inner classes de la fábrica . Esto funcionaría si tuviera una fábrica por clase, pero difícilmente es viable si tiene muchas clases administradas en una fábrica.
  2. Puede utilizar el modificador de acceso protected para restringir el acceso a los constructores de su clase . Esto es práctica común al usar el factory pattern.
+0

El primero es, como dijiste, tonto. El segundo tiene el problema de que la fábrica debe estar en el mismo paquete. – nrainer

+0

@nrainer :) Lo he usado en casos cuando tienes una fábrica para una sola clase con muchas opciones de creación de instancias, pero aparte de ese caso específico, no es aconsejable. –

1

Si te entiendo correctamente cuando dices "no permitir la creación de instancias directas de las clases para que sea más flexible", un patrón de fachada correctamente ejecutado se encargará de esto.

Restrinja los constructores de todas las clases que desea ocultar al alcance del paquete. Abra la clase de fachada al alcance público.

http://mindprod.com/jgloss/packagescope.html

"Si usted tiene una variable o método en el su clase que no desea que los clientes de su clase para acceder directamente, no darle un público, protegido o privado declaración. Debido a un descuido en el diseño de Java, no puede declarar explícitamente el la accesibilidad por defecto “paquete”. Otros miembros del paquete será capaz de verlo, pero clases fuera del paquete que 012.hereda de la tuya, no lo hará. El atributo de accesibilidad protegida ofrece algo más de visibilidad. Un método protegido es visible para clases heredadas, incluso no forma parte de el mismo paquete. Un método de alcance de paquete (predeterminado) no lo es. Esa es la única diferencia entre el alcance del paquete protegido y . "

+0

Lamentablemente, entonces la fachada debe estar en el mismo paquete. Como hay muchas clases, no quiero eso. – nrainer

+0

No he experimentado, pero deberías poder poner tu clase de fachada en un solo paquete y tener tus clases de implementación en paquetes para niños. De esta forma, la fachada y las clases de implementación están todas en el mismo paquete y obtienes la organización de tener muchos paquetes. – Speck

+1

Hasta donde yo sé, pck1.subPck1 no tiene nada que ver con pck1. Por lo tanto, no creo que funcione. (Los espacios de nombres en C# lo permitirían. De todos modos, si usaba C# no tendría este problema debido al modificador interno que resolvería mi problema.) – nrainer

0

Usted puede hacer este tipo de magia con un cargador de clases personalizadas, pero:

  • la correcta separación estará disponible sólo en un proyecto personal con su cargador de clases;
  • Es muy dudoso que el esfuerzo para crear tales cargador es digno.

en este tipo de situaciones me gustaría hacer algo similar a lo que podemos ver en el estándar de Java. Egyou ver javax.xml.stream.XMLInputFactory pero en algún lugar que tenga com.sun.xml.internal.stream.XMLInputFactoryImpl. Es perfectamente compilables si escribe:

new com.sun.xml.internal.stream.XMLInputFactoryImpl() 

pesar de que casi no lo hará :-) Con una propiedad del sistema es posible controlar la aplicación real que se está cargando. Para mí, ese enfoque está bien en muchas situaciones.

espero haber entendido bien su pregunta;)

Salud!

1

Hay dos soluciones a su pregunta que no implican mantener todas las clases en el mismo paquete.

El primero es utilizar el patrón Friend Accessor/Friend Package descrito en (Practical API Design, Tulach 2008).

El segundo es usar OSGi. Hay un artículo here explicando cómo OSGi logra esto.

preguntas relacionadas: 1, 2, 3 y 4.

Cuestiones relacionadas