Encapsulamento - Visibilidade: public, private

Computação II - Ciência da Computação


Prof.: Danilo S. Carvalho

Nessa aula, começaremos a tratar de mais um dos tópicos importantes para a Orientação a Objetos, e de sua aplicação à linguagem Java: Encapsulamento.


Ao final da aula, teremos como controlar a visibilidade dos detalhes de implementação da nossas classes.

Até esse ponto toda vez que criamos uma classe ou um método, utilizamos o modificador public.


E quando criamos variáveis ou atributos, não utilizamos tal modificador.

Mas o que significa esse modificador? Há outros? Quando precisamos usar?

Toda vez que declaramos uma classe, método ou campo, especificamos para este um modificador de acesso.

Esse modificador determina quais elementos do código poderão acessar aquilo que foi declarado.

O modificador public, permite o acesso por qualquer parte do programa.

Ou seja, podemos usar uma classe public em qualquer outra classe, de qualquer outro pacote.
No exemplo abaixo, podemos declarar uma variável do tipo Pessoa em qualquer parte do programa.

Já o modificador private, permite o acesso apenas pela classe (ou arquivo) em que o elemento foi declarado.

Uma classe private só pode ser usada nela mesma, o que não faz sentido, e por isso esse modificador não é usado dessa maneira.

No caso dos métodos e atributos, o modificador public permite o acesso a partir de uma instância da classe criada em qualquer parte do programa.

Logo, no exemplo abaixo, qualquer instância que eu criar da classe Pessoa vai permitir acesso ao campo cpf e ao método ler.

                        
                            public class Pessoa {
                                ...
                            }
                        
                    
                        
                            private class Pessoa {
                                ...
                            }
                        
                    
                        
                            public class Pessoa {
                                public String cpf;
                                ...

                                public void ler(Livro livro) {

                                }
                            }
                        
                    

Mas imagine agora a seguinte situação:

A administração da biblioteca descobriu que cada usuário possui uma atenção limitada a um certo número de páginas, após o qual as páginas lidas não são absorvidas e a pessoa vai ler o livro novamente, para continuar de onde parou.

Esse limite é estimado no momento da criação do registro da pessoa na biblioteca, dada a sua idade, e é usado para incrementar o número de páginas lidas, caso a pessoa leia um livro que ultrapasse o limite.

Entretanto, esse limite, e a forma como é utilizado pela classe são de interesse apenas da classe pessoa, já que deve apenas afetar o funcionamento de cada objeto do tipo pessoa.

Dessa forma, podemos alterar a maneira como o limite é estimado, ou como afeta os contadores de leitura a qualquer momento, sem afetar como o restante do programa utiliza os objetos desse tipo.

Para limitar o acesso de um campo ou método apenas à sua própria classe, usamos o modificador private.

No exemplo abaixo, o campo paginasAtento só pode ser acessado pelos métodos da classe Pessoa.

Para as demais classes do programa, é como se esse campo não existisse.

O mesmo vale para métodos private. Apenas a própria classe pode chamá-los.

                        
                            public class Pessoa {
                                ...
                                int paginasAtento;

                                public void ler(Livro livro) {
                                    ...
                                    this.paginasLidas += (livro.numPaginas > paginasAtento) ? 
                                                         paginasAtento : livro.numPaginas;
                                }
                            }
                        
                    
                        
                            public class Pessoa {
                                ...
                                private int paginasAtento;

                                public void ler(Livro livro) {
                                    ...
                                    this.paginasLidas += (livro.numPaginas > paginasAtento) ? 
                                                         paginasAtento : livro.numPaginas;
                                }
                            }
                        
                    

Além de public e private, há também o modificador protected, que permite que campos e métodos sejam acessados também por subclasses (falaremos sobre elas adiante).


Mas e quanto aos campos que deixamos sem modificador? Qual o tipo de acesso permitido?

Quando não usamos um modificador, os campos e métodos podem ser acessados por qualquer classe dentro do mesmo pacote.


Esse é o chamado modificador default.

Os modificadores de acesso são o primeiro aspecto de implementação de um conceito importantíssimo em Orientação a Objetos: o Encapsulamento.

Nesse contexto, encapsular significa ocultar os detalhes de implementação de uma unidade do programa, no caso as classes, para que outras partes do código não precisem fazer uso desses detalhes.

Dessa forma criamos módulos "caixa-preta", que nós e outros programadores podemos usar sem saber exatamente como funcionam.

Há várias vantagens nisso, mas as duas principais são:

1. Gastamos menos tempo analisando código, pois simplesmente usamos módulos já prontos (classes, pacotes), confiando na descrição do que eles fazem (Javadoc) sem ter de se preocupar com o como fazem.

Fazendo novamente uma analogia com automóveis, quando dirigimos um carro não estamos preocupados com os detalhes do funcionamento do motor, transmissão, etc., mas apenas em operar os controles do painel, volante e pedais.

2. Podemos mudar a implementação dos detalhes sem mudar a forma como as classes ou métodos são utilizados. Por exemplo, um método pode mudar completamente a forma de fazer algo (mais eficiência, acurácia, etc.), mantendo a mesma assinatura.

Da mesma forma que no mundo real, poderiamos modificar o motor de um carro e incluir um motor a jato.

O que deve fazer ele andar bem mais rápido, mas podemos manter o mesmo painél, volante e pedais, adicionando alguns botões opcionais (sobrecarga) para acionar o motor a jato.

Entendemos agora porque é interessante ocultar o funcionamento interno de uma classe e demos o primeiro passo em como fazer isso no Java com os modificadores de acesso.


Podemos imaginar que a nossas classes do sistema bancário podem se beneficiar bastante dessa forma de pensar. Que tal aplicar isso à elas.

Perguntas:

  1. Para o compilador Java, tentar acessar um campo inexistente de um objeto ou um campo private causa o mesmo resultado?
  2. Os campos e métodos privados aparecem no Javadoc?

Exercício:

  1. Modifique o código do sistema bancário simples, incorporando os modificadores de acesso private e protected onde aplicável e justificando a escolha do acesso.

Até a próxima aula!