procurando um caso de uso específico em que uma subclasse e uma classe dentro do mesmo pacote precisem acessar um campo ou método protegido ...
Bem, para mim, esse caso de uso é mais geral do que específico e deriva das minhas preferências:
- Comece com o modificador de acesso o mais rigoroso possível, recorrendo a um (s) mais fraco (s) somente mais tarde, conforme necessário.
- Os testes de unidade residem no mesmo pacote que o código testado.
Acima, eu posso começar a projetar para meus objetos com modificadores de acesso padrão (eu começaria, private
mas isso complicaria o teste de unidade):
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 lateral no trecho acima, Unit1
, Unit2
e UnitTest
são aninhados dentro Example
de simplicidade de apresentação, mas em um projeto real, eu provavelmente teria essas classes em arquivos separados (e UnitTest
até mesmo em um diretório separado ).
Então, quando surgir uma necessidade, eu enfraqueceria o controle de acesso do padrão para 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();
}
}
}
Veja bem, eu posso manter o código de teste de unidade ExampleEvolved
inalterado devido ao acesso a métodos protegidos do mesmo pacote, mesmo que acessar objeto não seja uma subclasse .
Menos mudanças necessárias => modificação mais segura; afinal, mudei apenas os modificadores de acesso e não modifiquei os métodos Unit1.doSomething()
e o que Unit2.doSomething()
faço, por isso é natural esperar que o código de teste de unidade continue sendo executado sem modificações.
protected
é apenas subclasse? Honestamente, há muito tempo, eu estava sob a impressão de que esse é o comportamentoprotected
é apenas de classe e subclasse einternal
é de toda a biblioteca / pacote. Ele também possuiprotected internal
o equivalente ao Javaprotected
.IMHO, essa foi uma má decisão de design em Java.
Apenas especulando, mas acho que eles queriam que os níveis de acesso estivessem em uma progressão estrita: privado - "pacote" - protegido - público. Eles não queriam ter uma hierarquia, onde alguns campos estariam disponíveis para o pacote, mas não as subclasses, alguns disponíveis para as subclasses, mas não o pacote, e alguns ambos.
Ainda assim, na minha humilde opinião, eles deveriam ter seguido o contrário: Disse que protected é visível apenas para a classe e subclasses, e esse pacote é visível para a classe, subclasses e pacote.
Costumo ter dados em uma classe que precisa estar acessível para subclasses, mas não para o restante do pacote. Estou com dificuldade para pensar em um caso em que o inverso era verdadeiro. Tive algumas raras ocasiões em que tive um pacote de classes inter-relacionadas que precisam compartilhar dados, mas que devem mantê-los protegidos de fora do pacote. Tudo bem, coloque-os em um pacote, etc. Mas nunca tive um caso em que quero que o pacote compartilhe dados, mas quero mantê-lo de subclasses. Ok, eu posso imaginar a situação chegando. Suponho que se esse pacote fizer parte de uma biblioteca que possa ser estendida por classes que eu não conheço, pelas mesmas razões pelas quais tornaria os dados em uma classe privados. Mas é muito mais comum querer disponibilizar dados apenas para a classe e seus filhos.
Há muitas coisas que mantenho em segredo entre mim e meus filhos e não compartilhamos com os vizinhos. Há muito pouco que eu mantenho em segredo entre mim e os vizinhos e não compartilho com meus filhos. :-)
fonte
Um bom exemplo que vem imediatamente à mente são as classes de utilitários que são muito usadas no pacote, mas você não deseja acesso público (classes de carregamento de imagem nos bastidores, classes de criação / destruição dos bastidores, etc.) .) em vez de disponibilizar tudo [equivalente a Java
friend access modifier or idiom
emC++
] de todas as outras classes, tudo fica automaticamente disponível.fonte
Os casos de uso do modificador de acesso protegido / pacote são semelhantes aos dos modificadores de acesso a amigos em C ++.
Um caso de uso é ao implementar o padrão Memento .
O objeto de lembrança precisa acessar o estado interno de um objeto, mantê-lo, para servir como um ponto de verificação para operações de desfazer.
Declarar a classe no mesmo pacote é uma das maneiras possíveis de obter o padrão Memento, pois o Java não possui modificador de acesso "amigo" .
fonte
simetria?
É raro precisar desse acesso, e é por isso que o acesso padrão é tão raramente usado. Às vezes, porém, as estruturas desejam o código gerado, onde as classes de wrapper são colocadas no mesmo pacote que interage diretamente com suas classes, acessando membros em vez de acessadores por razões de desempenho. Pense no GWT.
fonte
A hierarquia de encapsulamento do Java está bem definida:
Classe -> Pacote -> Herança
"Protected" é apenas uma forma mais fraca de privacidade do que o padrão do pacote, conforme decidido pelos designers de Java. O acesso aos itens padrão do pacote é restrito a um subconjunto das entidades que têm permissão para acessar itens protegidos.
Do ponto de vista matemático e de implementação, faz muito sentido que seus conjuntos de entidades com permissão para acessar itens sejam aninhados. (Você não pode aninhar seu conjunto de acesso a pacotes dentro do conjunto de acesso protegido porque as classes têm permissão para herdar de outros pacotes).
Do ponto de vista conceitual, faz sentido que algo no java.util seja "mais amigável" com outra classe no pacote do que algo no com.example.foo.bar que a está subclassificando. No primeiro caso, as classes provavelmente serão escritas pelo mesmo autor, ou pelo menos codificadores da mesma organização.
fonte