Escondendo classs em um arquivo jar

É realmente impossível esconder algumas classs em um arquivo jar?

Eu não queria permitir a instanciação direta das classs para mantê-las mais flexíveis. Somente a fábrica (ou fachada) deve ser visível deste flask.

Existe outra maneira de resolver este problema do que criar dois projetos? (Dois projetos: o primeiro contém as classs (implementação) e o outro faz referência ao primeiro e contém a fábrica; depois, apenas o segundo será referenciado)

Eu acho que você terá qualquer falha do compilador ou aviso se o seu método de fábrica pública tentar retornar algo que está “oculto”.

Não, você não pode ocultar uma class pública sem reimplementar seu próprio ClassLoader ou usar o OSGi ou algo semelhante.

O que você pode fazer é separar a API da interface da implementação, por exemplo, ter um projeto que contenha apenas as interfaces e outro object que contenha as implementações. No entanto, você ainda não pode ocultar as classs de implementação.

Eu estou entendendo que você não está olhando para esconder as classs reais, apenas impedir a sua construção fora de uma class de fábrica. Isso pode ser facilmente alcançado usando a visibilidade privada do pacote (padrão) nos construtores de class. A única limitação é que você precisará ter as classs e a fábrica no mesmo pacote, de modo que, em uma base de código média a grande, as coisas podem ficar desnecessariamente complexas.

Se eu entendi sua pergunta corretamente, você gostaria de ter certeza de que os usuários da sua biblioteca são forçados a usar sua fábrica para instanciar seus objects, em vez de usar os próprios construtores.

Do meu ponto de vista, há duas possibilidades, uma das quais é tola, mas utilizável em poucos casos específicos, e a outra é a maneira mais prática e provavelmente mais comum de se fazer isso.

  1. Você poderia fazer todas as suas aulas em classs internas privadas da fábrica. Isso funcionaria se você tivesse uma fábrica por class, mas dificilmente é viável se você tiver muitas classs diferentes sendo gerenciadas através de uma fábrica.
  2. Você pode usar o modificador de access protected para restringir o access a seus construtores de class. Essa é uma prática comum ao usar o padrão de fábrica .

Ofuscação pode ajudá-lo de alguma forma .

Com os carregadores de classs padrão, um arquivo jar antigo não é possível. Conhece este conceito de tornar visíveis para um outro pacote apenas alguns pacotes e não outros (isto é, separação da API pública e implementação interna).

Se você é usinf eclipse você pode aplicar essas regras com este

Se eu entendi corretamente quando você diz “não permitir instanciação direta das classs para mantê-lo mais flexível”, um padrão de fachada corretamente executado irá lidar com isso.

Restringir os construtores de todas as classs que você deseja ocultar para o escopo do pacote. Abra a class de fachada para o escopo público.

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

“Se você tem uma variável ou método em sua class que você não quer que os clientes de sua class acessem diretamente, não dê a ela uma declaração pública, protegida ou privada. Devido a um descuido no design de Java, você pode ‘ • Declarar explicitamente a acessibilidade “pacote” padrão. Outros membros do pacote poderão vê-lo, mas as classs fora do pacote que herdam da sua não o verão.O atributo de acessibilidade protegida oferece um pouco mais de visibilidade. para herdar classs, mesmo que não faça parte do mesmo pacote. Um método de escopo de pacote (padrão) não é. Essa é a única diferença entre escopo de pacote e protegido. ”

Existem duas soluções para sua pergunta que não envolvem manter todas as classs no mesmo pacote.

A primeira é usar o padrão Friend Accessor / Friend Package descrito em (Practical API Design, Tulach 2008).

A segunda é usar o OSGi. Há um artigo aqui explicando como o OSGi realiza isso.

Questões relacionadas: 1 , 2 , 3 e 4 .

Você pode fazer essas magias com um carregador de classs personalizado, mas:

  • a separação correta estará disponível apenas em um projeto com seu carregador de classs;
  • é realmente duvidoso que o esforço para criar esse carregador seja digno.

Em tais situações, eu faria algo semelhante ao que podemos ver no Java padrão. Por exemplo, você vê javax.xml.stream.XMLInputFactory mas em algum lugar você tem com.sun.xml.internal.stream.XMLInputFactoryImpl . É perfeitamente compilável se você escrever:

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

embora você dificilmente faça isso 🙂 Com uma propriedade do sistema, você pode controlar a implementação real que está sendo carregada. Para mim, essa abordagem é boa em muitas situações.

Espero ter entendido sua pergunta corretamente;)

Felicidades!

Intereting Posts