Encapsulamento

Encapsulamento

Encapsular, nada mais é do que proteger membros de outra classe de acesso externo, permitindo somente sua manipulação de forma indireta. Isso é possível da seguinte maneira:

Consideremos o seguinte exemplo de uma classe Livro:

package br.encapsulamento;

/**
 * Classe utilizada para representar o Livro.
 */
public class Livro {
    private String titulo;
    private String autor;

    public String getAutor() {
        return autor;
    }

    public void setAutor(String autor) {
        this.autor = autor;
    }

    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }
}

Note que os dois atributos da classe (titulo e autor) são do tipo private, que permite apenas o acesso destas informações a partir da própria classe, logo para que seja possível ler ou alterar essas informações criamos métodos ditos métodos assessores ou então getters e setters.

A princípio parece ser algo sem muita utilidade, mas desta forma podemos criar atributos os quais podemos apenas ler informações ou ainda gerar tratamentos específicos sempre que outra classe solicita a alteração de um atributo de nossa classe.

Encapsule aquilo que pode ser alterado com frequência na sua aplicação, por exemplo:

package br.encapsulamento;

/**
 * Classe utilizada para representar um Professor
 */
public class Professor {
    private int registro;
    private String nome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getRegistro() {
        return registro;
    }

    public void setRegistro(int registro) {
        this.registro = registro;
    }
}
package br.encapsulamento;

/**
 * Classe utilizada para representar um Aluno.
 */
public class Aluno {
    private int matricula;
    private String nome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getMatricula() {
        return matricula;
    }

    public void setMatricula(int matricula) {
        this.matricula = matricula;
    }
}

Note que os atributos das classes Professor e Aluno possuem a visibilidade private, dessa forma eles só podem ser acessados pelas suas classes, também criamos métodos set (métodos utilizados para alterar o valor de uma propriedade) e get (método utilizado para obter o valor de uma propriedade) para cada atributo.

Dado a classe Professor e Aluno, queremos consultar os alunos e professores pelo nome:

package br.encapsulamento;

/**
 * Classe utilizada para consultar os alunos e professores
 * através de seu nome.
 */
public class Consultar {
    public Aluno[] consultarAlunoPorNome(Aluno[] alunos, String nome) {
        Aluno[] alunosEncontrados = new Aluno[alunos.length];
        int contAlunos = 0;

        for(int i = 0; i < alunos.length; i++) {
            if(alunos[i].getNome().equals(nome)) {
                alunosEncontrados[contAlunos++] = alunos[i];
            }
        }

        Aluno[] retorno = new Aluno[contAlunos];
        for(int i = 0; i < contAlunos; i++) {
            retorno[i] = alunosEncontrados[i];
        }

        return retorno;
    }

    public Professor[] consultarProfessorPorNome(Professor[] professores,
String nome) {
        Professor[] profEncontrados = new Professor[professores.length];
        int contProfessores = 0;

        for(int i = 0; i < professores.length; i++) {
            if(professores[i].getNome().equals(nome)) {
                profEncontrados[contProfessores++] = professores[i];
            }
        }

        Professor[] retorno = new Professor[contProfessores];
        for(int i = 0; i < contProfessores; i++) {
            retorno[i] = profEncontrados[i];
        }

        return retorno;
    }
}

Agora digamos que nosso programa que busca os alunos e professores esta funcionando corretamente, e precisamos adicionar outra busca que procura coordenadores pelo seu nome.

package br.encapsulamento;

/**
 * Classe utilizada para representar um Coordenador.
 */
public class Coordenador {
    private String cursoCoordenado;
    private String nome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getCursoCoordenado() {
        return cursoCoordenado;
    }

    public void setCursoCoordenado(String cursoCoordenado) {
        this.cursoCoordenado = cursoCoordenado;
    }
}

Para consultar o coordenador pelo nome, precisamos usar um método bem parecido com o que consulta o aluno e professor, mas se notarmos as classes Aluno, Professor e Coordenador tem o atributo nome em comum e é exatamente por este atributo que os consultamos.

Se criarmos uma classe Pessoa para ser uma classe Pai dessas classes e se a classe Pai tiver o atributo nome, então todas as subclasses recebem este atributo por herança:

package br.encapsulamento;

/**
 * Classe utilizada para representar um Pessoa.
 */
public class Pessoa {
    private String nome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }
}

As subclasses Professor, Aluno e Coordenador ficaram da seguinte forma:

package br.encapsulamento;

/**
 * Classe utilizada para representar um Professor.
 */
public class Professor extends Pessoa {
    private int registro;

    public int getRegistro() {
        return registro;
    }

    public void setRegistro(int registro) {
        this.registro = registro;
    }
}
package br.encapsulamento;

/**
 * Classe utilizada para representar um Aluno.
 */
public class Aluno extends Pessoa {
    private int matricula;

    public int getMatricula() {
        return matricula;
    }

    public void setMatricula(int matricula) {
        this.matricula = matricula;
    }
}
package br.encapsulamento;

/**
 * Classe utilizada para representar o Coordenador.
 */
public class Coordenador extends Pessoa {
    private String cursoCoordenado;

    public String getCursoCoordenado() {
        return cursoCoordenado;
    }

    public void setCursoCoordenado(String cursoCoordenado) {
        this.cursoCoordenado = cursoCoordenado;
    }
}

Para consultar o Aluno, Professor e Coordenador vamos criar apenas um método que recebe um vetor de Pessoa e o nome que será procurado e retorna um vetor com as Pessoas encontradas:

package br.encapsulamento;

/**
 * Classe utilizada para consultar de uma forma genérica qualquer
 * subclasse de Pessoa através de seu nome.
 */
public class ConsultarPessoa {
    public Pessoa[] consultarAlunoPorNome(Pessoa[] pessoas, String nome) {
        Pessoa[] pessoasEncontradas = new Pessoa[pessoas.length];
        int contPessoas = 0;

        for(int i = 0; i < pessoas.length; i++) {
            if(pessoas[i].getNome().equals(nome)) {
                pessoasEncontradas[contPessoas++] = pessoas[i];
            }
        }

        Pessoa[] retorno = new Pessoa[contPessoas];
        for(int i = 0; i < contPessoas; i++) {
            retorno[i] = pessoasEncontradas[i];
        }

        return retorno;
    }
}

Dessa forma usamos herança e encapsulamos a forma de encontrar um Aluno, Pessoa e Coordenador, agora se tivermos que adicionar um Diretor, por exemplo, nosso método de consulta não precisa ser alterado, precisamos apenas criar a classe Diretor e fazer ela filha da classe Pessoa.