Como encapsular classes internas em uma API escrita em Java?


9

Temos que escrever uma biblioteca. Naturalmente, ele deve ter apenas uma API muito pequena (o mais amplo possível, o menor possível). Os internos da biblioteca são um pouco complexos. Portanto, eles precisam de estruturação.

Atualmente, para a estruturação, vejo duas maneiras:

1. use pacotes.

profissionais: a biblioteca pode ser bem estruturada. Tudo em seu lugar.

contras: o uso de classes através das bordas dos pacotes precisa de classes públicas e, portanto, amplia a API de toda a biblioteca.

2. use classes internas estáticas, tudo em um pacote.

profissionais: são necessárias muito poucas coisas públicas (classes, métodos etc.).

contras: as classes estão ocultas apenas para estruturá-las. Esse seria um dos poucos casos de uso em que existem tantas classes internas estáticas usadas. Os desenvolvedores não estão acostumados a isso e podem ignorá-los.


Existe uma maneira melhor de obter uma API pequena em uma biblioteca bem estruturada?

Edit: Eu esqueci de mencionar: é para uma biblioteca Android. Portanto, não java9.


Por que suas classes internas precisam ser estáticas?
David Arno

As classes internas não aumentam as unidades de código? Quero dizer que uma classe com várias classes internas pode se tornar muito longa.
Tulains Córdova 01/12/16

2
@ TulainsCórdova, bom ponto, eu li o termo "interno" como "interno", que eu acho que Java chama de "pacote privado". A maneira normal de criar uma lib é certamente ter um pacote, contendo algumas classes públicas, com todo o resto interno / privado do pacote.
David Arno

Olá, @frmarkus. Tentei reescrever o título da sua pergunta para ser mais específico e evitar votos "pouco claros do que você está pedindo". Sinta-se à vontade para editá-lo novamente, se achar que ele deturpa sua pergunta real.
Andres F.

11
@ TulainsCórdova: Sim, as unidades de código são muito grandes (3 mil linhas de código por arquivo). Esse é outro problema importante dessa maneira de estruturar.
Markus Frauenfelder

Respostas:


1

Eu vejo o que você está fazendo com 2. Você está usando classes como pacotes e pacotes como módulos, para que você possa se isolar dentro do pacote, mas ainda assim se organizar dentro do pacote usando classes.

Isso é muito inteligente. Cuidado com astúcia.

Isso forçará você a bloquear várias classes no mesmo arquivo de origem (o que você prefere) e o caminho terá uma palavra em maiúscula extra.

Isso também forçará você a escrever qualquer código de teste dentro do pacote, a menos que você use a reflexão para invadir seu caminho de fora.

Fora isso, isso funcionará. Vai parecer estranho.

As pessoas estão mais acostumadas às classes internas usadas como EntrySet no Hashtable. É privado, então eu não posso criá-lo, mas implementa uma interface pública, então eu apenas falo com ele através da interface e tenho algo que você precisa.

Mas você está descrevendo classes com as quais não quer que eu converse, mesmo através de uma interface. Portanto, nenhuma interface para mim. Isso significa que não tenho nada para olhar e me confundir (a menos que você me forneça a fonte).

O maior problema que prevejo é que esses novatos confusos mantêm a API. Você pode enviar documentação e comentários para eles, mas não será superdimensionado quando eles não lerem ou confiarem em nenhum deles.

Você criou outro padrão que compensa uma deficiência no idioma. Java não possui modificador de acesso que conceda acesso a um grupo de pacotes. Ouvi dizer que um modificador de acesso "módulo" havia sido proposto, mas não vejo sinal disso.

O modificador de acesso padrão (sem modificador) provavelmente é o que você usará aqui, a menos que você não se importe de me infiltrar na herança, nesse caso protegido.

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N 

O que você realmente deseja é acesso ao módulo. Dessa forma, você pode manter seus testes em um pacote e código em outro. Infelizmente, não o temos em Java.

A maioria das pessoas faz apenas 1 e expande a API. O uso adequado de interfaces mantém a pressão fora da implementação.

Hackear o que você deseja no 1 é ainda mais feio. Dê uma olhada na pilha de chamadas e lance uma exceção sempre que o que você chamou é de um pacote que você não gosta. Eeew.


2

Por todos os meios, separe seu código em pacotes. Isso ajudará muito a melhorar a manutenção.

Para impedir que os usuários finais acessem coisas que não deveriam, você precisa separar sua API em interface e implementação.

Você pode fazer isso literalmente, definindo a API inteira em termos de interfaces Java e fornecendo um número de classes de fábrica para produzir objetos de implementação. É isso que o JDBC faz.

Ou você pode fazer isso por convenção, criando internalpacotes e documentando esses pacotes como dependentes da implementação e sujeitos a alterações sem aviso ou compatibilidade com versões anteriores.


11
Infelizmente, este é um processo completo. Isso deixa para muitas classes públicas. Eles podem ter dicas (sejam fábricas ou 'internas'). Mas eu tenho que aplicar ferramentas adicionais a eles (a todas as classes públicas), isso simplesmente não é bom.
Markus Frauenfelder

@frmarkus - Eu acho que (1) você espera demais dos controles de acesso ou (2) precisa repensar sua estrutura de pacotes para que as classes de um pacote não precisem depender das classes de outro pacote (se você pode manter tudo como classes aninhadas estáticas, isso não deve ser difícil).
Kdgregory
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.