Você está na página 1de 85

Padrões de Projeto

LIVRO 01
Introdução a Orientação a Objetos
Sumário

1. Introdução 3. Intermediário 4. Avançado


2. Básico Encapsulamento Reescrita (sobrescrita)
Projeto Associação Sobrecarga
Classe de objetos Construtor Polimorfismo
Classe Principal (main) Atributo estático Classe abstrata
Objeto Herança Método abstrato
Referência Interface
Comportamento (método) 5. Finalizando
Documentando com comentários
6. Referências
Introdução
Neste primeiro livro vamos revisar os conceitos básicos da orientação a objetos, apresentando estes conceitos
através de três dimensões. A primeira dimensão é o Caso de Uso. Aqui vamos descrever textualmente a situação
problema a ser enfrentada.

A segunda dimensão é o Diagrama Conceitual. Aqui


vamos utilizar modelagem UML, através de
Orientação a Objetos, para descrever
visualmente qual solução será adotada
para resolver o problema descrito no
Caso de Uso.

A terceira dimensão é a implementação.


Aqui vamos apresentar o caminho, passo
a passo, para transformar a modelagem
da solução em um código de programação.
Para implementar a solução, vamos utilizar
a linguagem Java.

1 2 3 4 5 6 7 8 9 10
Projeto Caso de Uso e Diagrama Conceitual

Caso de Uso Diagrama Conceitual


Precisamos criar um projeto que implemente
sistema de um banco.

O primeiro passo para implementar este sistema é banco


criar um projeto.

Neste caso vamos utilizar a linguagem Java, no


ambiente Eclipse.

No Diagrama apresentado, o banco é o sistema. Ele é


representado por um limite (linha pontilhada) que engloba tudo
que será implementado.

1 2 3 4 5 6 7 8 9 10
Projeto Implementação
Passo 1: abra o Eclipse
Normalmente, o Eclipse se divide nestas três janelas,
que podem ser alteradas clicando em Windows ­>
Show View.

Para criar um projeto, clique no link, ou clique em File ­>


New ­> Java Project.

1 2 3 4 5 6 7 8 9 10
Projeto Implementação
Passo 2: crie o projeto
É incluído a janela Package Explorer do projeto ”banco”.
Neste projeto, o Eclipse já inclui uma pasta chamada “JRE
System Library”.
JRE (Java Runtime Environment) é uma camada de software
que é executado sobre um software de sistema operacional
de um computador e fornece as bibliotecas de classe e
outros recursos
que um programa específico do Java precisa executar.
A Biblioteca de Sistema JRE possui os recursos necessários
que o programa “banco” irá
precisar para ser executado
com sucesso.
Já a pasta “src” é o local
aonde ficarão as classes
que criaremos, ou seja,
todo o código fonte do
programa fica aqui.

1 2 3 4 5 6 7 8 9 10
Classe de Objetos Caso de Uso e Diagrama conceitual

Agora precisamos definir que tipos de


objetos teremos em nosso banco, os tipos banco
de objeto são chamados de classes.
Nome da classe, que tem a letra
Conta maiúscula por ser uma classe
A menor unidade que temos em um banco saldo
é a conta bancária, e no nosso caso, a agência
conta tem características, chamadas de número
titular
atributos, que no caso da conta
podemos ter: saldo, agência, número e Atributos: são características,
propriedades da classe.
nome do titular. Atributos tem nome com letra
minúscula.

Todas as classes estão dentro do projeto


banco.

1 2 3 4 5 6 7 8 9 10
Classe de Objetos Implementação
Passo 1: crie uma classe de objeto
Clique com o
botão direito na
pasta “scr” e
acesse a opção
New ­> Class.

1 2 3 4 5 6 7 8 9 10
Classe de Objetos Implementação

Passo 2: o que acontece


O resultado será a inclusão da classe “Conta” no projeto ”banco”. Ao lado, já
aparece o código do arquivo Conta.java.
Importante dizer que ainda não criamos nenhum objeto Conta, definimos a
classe “Conta” que nos permitirá criar objetos Conta no futuro.
Observe que antes do nome da classe o Eclipse acrescenta a informação
“public”. Isso significa que outras classes poderão acessar esta classe que
você criou.
Observe também que o Eclipse cria um pacote (package) para guardar
todas as classes do projeto, mas isso não é necessário.

1 2 3 4 5 6 7 8 9 10
Classe de Objetos Implementação
Passo 3: crie os atributos da classe Conta
Estes atributos serão descritos dentro da classe, e cada um deve ter definido
o tipo de informação que pode conter. public class Conta {
Para saldo, usaremos o tipo double, pois ele armazena dados de ponto double saldo;
flutuante. int agência;
Os componentes “agencia” e “numero” serão do tipo int. Para finalizar, titular
int número;
String titular;
será uma String, que guarda um conteúdo de texto. }
A String começa com letra maiúscula porque trata­se de uma classe.
Clique “Ctrl + S” para salvar a classe modificada.
Ao lado você observa a localização física do arquivo fonte da classe.

1 2 3 4 5 6 7 8 9 10
Classe Principal (main) Caso de Uso e Diagrama Conceitual

Os objetos somente são criados durante


a execução do sofware. Para que o banco
software seja executado, precisamos criar
uma outra classe que vai criar os objetos Principal Conta
conta.
saldo
agência
Esta nova classe será a primeira classe a número
ser executada pelo Java, por isso vamos titular
chama­la de Principal.Para que a classe main
Principal seja a primeira a ser executada,
Métodos são as
ela precisa ter um método chamado partes executáveis
main. da classe.

1 2 3 4 5 6 7 8 9 10
Classe Principal (main) Implementação
Passo 1: crie a classe Principal
Clique com o botão direito na pasta “scr” e
acesse a opção New ­> Class.
Siga a orientação nas caixas ao lado.
O resultado será a inclusão da classe
“Principal” no projeto ”banco”.
Clique “Ctrl + S” para salvar a classe.

1 2 3 4 5 6 7 8 9 10
Classe Principal (main) Implementação
Passo 2: analise o código
Ao lado, temos o código do arquivo Principal.java.
O Eclipse inclui a chamada ao método main na classe principal. Este public class Principal {
método é: public static void main(String[] args) {
• Public, porque poderá ser acesso por outras classes, // TODO Auto-generated method stub
• Static, porque quando a classe Principal for chamada, este }
método será executado,
• Void, porque não retornará nenhuma informação quando for
}
executado.
O Eclipse acrescenta também um comentário, que iremos excluir.

1 2 3 4 5 6 7 8 9 10
Objeto Caso de Uso e Diagrama Conceitual

Para criar objetos a partir de


classes, precisamos criar a classe banco
Principal que vai criar as contas.
Principal Conta
É nesta nova classe que vamos saldo
agência
poder criar instâncias da classe número
Conta. titular
main

Este processo de criar objetos é


chamado de instanciação,
porque objetos são conhecidos
como instâncias de uma classe. conta1 conta2 conta3
saldo = 200 saldo = 150 saldo = 300
agência = 30 agência = 30 agência = 45
número = 1 número = 2 número = 3
titular = Marco titular = João titular = Ana

1 2 3 4 5 6 7 8 9 10
Objeto Implementação
Passo 1: crie um objeto da classe Conta
Para criar um novo objeto, basta informar a Temos um programa válido, que inclusive
palavra new junto com o nome da classe, pode ser executado, mas que não vai gerar
acrescentando dois parênteses (). nenhum resultado visível.
Estes parênteses indicam que o novo objeto Vamos então colocar um saldo de 200 reais
será criado sem a necessidade de passar nesta conta.
parâmetros para o método de criação.

public class Principal { public class Principal {


public static void main(String[] args) { public static void main(String[] args) {
new Conta(); new Conta();
saldo = 200;
}
} }
}

1 2 3 4 5 6 7 8 9 10
Objeto Implementação
Passo 2: execute o programa
A questão é que não está claro a qual
objeto este saldo se refere.
Ao tentar executar este programa o Eclipse
vai retornar uma mensagem de erro.

1 2 3 4 5 6 7 8 9 10
Objeto Implementação
Passo 3: corrija os erros
Nós não informamos a qual objeto A execução vai retornar no console não Voltamos a ter apenas um erro, que é:
pertence este saldo. Para isso, temos que um, mas dois erros, porque a variável não identificamos a qual objeto o saldo
guardar o retorno de new Conta(), que é conta1 não teve seu tipo declarada. O se refere. Para resolver, incluímos o nome
um objeto, em uma variável. tipo da variável conta1 é Conta. do objeto antes do atributo.
Execute de novo. Execute de novo. Execute de novo.

public class Principal { public class Principal { public class Principal {


public static void main(String[] args) { public static void main(String[] args) { public static void main(String[] args) {
conta1 = new Conta(); Conta conta1 = new Conta(); Conta conta1 = new Conta();
saldo = 200; saldo = 200; conta1 .saldo = 200;
} } }
} } }

1 2 3 4 5 6 7 8 9 10
Objeto Implementação
Passo 4: execute apresentando o saldo na tela
Ao rodar o programa, nada acontece. Não temos mais erro na console, mas também
não temos nenhuma mensagem informando que o programa foi executado. Vamos
então mostrar o valor do saldo na tela.

Vamos imprimir o valor 200 acessando o atributo saldo de conta1. Através do atalho
sysout e depois "Ctrl + Space", será mostrado o System.out.println(), e então
imprimiremos o atributo saldo do objeto conta1.

Ao executarmos aplicação, o resultado


será o valor do saldo da conta
public class Principal {
específica referenciada, ou seja, 200. public static void main(String[] args) {
Conta conta1 = new Conta();
conta1 .saldo = 200;
System.out.println(conta1 .saldo);
}
}

1 2 3 4 5 6 7 8 9 10
Objeto Implementação
public class Principal {

Passo 5: crie outras instâncias da classe Conta, public static void main(String[] args) {
Conta conta1 = new Conta();
informando todos os atributos conta1 .saldo = 200;
conta1 .agência = 30;
Vamos criar os objetos conta2 e conta3. conta1 .número = 1 ;
conta1 .titular = “Marco”
Logo em seguida vamos definir os valores de todos os atributos de
cada objeto. Mas é importante saber que quando criamos objetos, Conta conta2 = new Conta();
todos os atributos daquele novo objeto são preenchidos com valores conta2.saldo = 1 50;
conta2.agência = 30;
default. conta2.número = 2;
0 é o valor default de vários tipos numéricos, como int, double e long. conta2.titular = “João”

No caso do tipo boolean o valor é false. Conta conta3 = new Conta();


conta3.saldo = 300;
conta3.agência = 45;
conta3.número = 3;
conta3.titular = “Ana”
System.out.println(“O saldo da conta 1 é “+ conta1 .saldo);
System.out.println(“O saldo da conta 2 é “+ conta2.saldo);
System.out.println(“O saldo da conta 3 é “+ conta2.saldo);
}
}

1 2 3 4 5 6 7 8 9 10
Objeto Implementação
Passo 6: execute o programa
Ao rodar o programa, você pode ver os println na console, informando
o saldo de cada conta.

1 2 3 4 5 6 7 8 9 10
Referência Caso de Uso e Diagrama Conceitual

Quando criamos um novo objeto


e vinculamos a uma variável, banco
esta variável não guarda o
objeto em si, mas uma referência
ao endereço da área de variavel conta1
memória aonde o objeto está
armazenado.
variável outra
Para entender o conceito de
referência, vamos criar uma nova conta1
classe TesteReferencia, que saldo = 200
agência = 30
também terá o método main. número = 1
titular = Marco

1 2 3 4 5 6 7 8 9 10
Referência Implementação
Passo 1: crie a classe TesteReferencia
public class TestaReferencia {
Para isso, basta seguir os passos que usamos para criar a
classe Principal. public static void main(String[] args) {
Conta conta1 = new Conta();
Passo 2: crie um objeto da classe Conta conta1 .saldo = 200;
Crie novamente o objeto conta1, e atribua um saldo de System.out.println("O saldo da conta 1 é "+ conta1 .saldo); }
200 reais. Em seguida, imprima o saldo de conta1. }
Execute o programa.
Estamos executando agora outra classe que possui main. E
ao rodar o programa, mostramos o valor do saldo na tela. public class TestaReferencia {
public static void main(String[] args) {
Passo 3: crie uma variável do tipo conta Conta conta1 = new Conta();
Crie uma variável do tipo Conta e guarde nela a conta1.
conta1 .saldo = 200;
System.out.println("O saldo da conta 1 é "+ conta1 .saldo);
Conta outra = conta1 ;
} }

1 2 3 4 5 6 7 8 9 10
Referência Implementação
Passo 4: imprima o saldo dos objetos
public class TestaReferencia {
Quando fazemos esta operação não estamos criando um novo
objeto, estão na verdade criando uma nova referência ao public static void main(String[] args) {
objeto que já existia. Conta conta1 = new Conta();
conta1 .saldo = 200;
Para provar isso, acrescente
50 reais no saldo de conta1, System.out.println("O saldo da conta 1 é "+ conta1 .saldo);
e imprima o saldo da
Conta outra = conta1 ;
referência outra.
System.out.println("Somamos 50 na conta 1 ");
Podemos observar pela console que ao alterar conta1 e conta1 .saldo = conta1 .saldo + 50;
mostrar outra, é como se estivéssemos falando do mesmo
System.out.println("O saldo de outra é "+ outra.saldo);
objeto. E na verdade estamos mesmo. }
Apresentamos então o resultado que foi mostrado no diagrama }
conceitual, são duas referências para um mesmo objeto.

Complementando, se executarmos o comando System.out.println(conta1), não vamos imprimir o objeto, mas sim a referência
ao local de memória deste objeto.

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Caso de Uso e
Diagrama Conceitual

Além dos atributos, as classes de objeto também


podem ter comportamento. Os comportamentos banco
definem como as classes reagem quando são
provocadas.
Conta
saldo
O comportamento pode alterar os atributos do agência
objeto, podem receber parâmetros e devolver número
titular
parâmetros para o ambiente também.
deposita
saca
Métodos: são os
Quando implementamos comportamentos em Java comportamentos
transfere

chamamos de método. da classe.

A classe Conta terá os comportamentos deposita


(inclui dinheiro na conta), saca (retira dinheiro da
conta) e transfere (retira dinheiro de uma conta e No Diagrama apresentado, a Conta começa com letra maiúscula por ser
coloca em outra conta). uma classe, e deposita, saca e transfere começam em letra minúscula por
serem métodos. Todas as classes estão dentro do projeto banco.

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 1: inclua o método deposita na classe Conta
Os métodos são incluídos dentro do código da classe, logo após
a lista de atributos. public class Conta {
O “void” antes do nome significa que este método não retorna
nenhuma informação para o ambiente.
double saldo;
int agência;
Entre parênteses ficam as informações (parâmetros) que serão int número;
passadas para o método. String titular;
Entre chaves fica o código, ou seja, o que o método vai executar public void deposita(double valor) {
quando for chamado.
}
Da maneira como está, este código compila sem dar nenhum erro. }
Mas para padronizar a programação, e informar que este método
pode ser acessado por todo o ambiente do banco, vamos incluir
“public”.

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 2: defina o que o método faz
Este método deve somar o valor que chegou como parâmetro ao
atributo saldo. public class Conta {
double saldo;
int agência;
int número;
String titular;
public void deposita(double valor) {
saldo = saldo + valor;
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 3: crie uma classe TestaMetodo
Vamos criar uma classe para testar o método
deposita. O nome desta classe será public class TestaMetodo {
TestaMetodo.
O código desta nova classe está a seguir:
public static void main(String[] args) {
Conta novaconta = new Conta();
Ao executar a classe TestaMetodo, o console System.out.println("O saldo da conta é "+ novaconta.saldo);
mostra primeiro o saldo zerado, depois mostra
novamente, mas agora o saldo é 50,0 porque novaconta.deposita(50);
utilizamos antes o método deposita. System.out.println("O saldo da conta é "+ novaconta.saldo);
}
}

Agora vamos discutir algo muito importante, que é a maneira


como nos referimos aos atributos da classe.

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 4: incluindo um erro no código
No exemplo anterior, eu criei uma nova conta chamada
novaconta. Eu poderia me referir diretamente a este objeto public class Conta {
dentro do método?
Veja como ficaria, ao lado.
double saldo;
int agência;
Ao tentar executar o TestaMetodo novamente, aparece um erro int número;
no console, dizendo que não conhece novaconta. String titular;
E isso é verdade, porque novaconta existe apenas no espaço public void deposita(double valor) {
da classe TestaMetodo.
. novaconta.saldo = novaconta.saldo + valor;
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 5: incluindo a referência this
Quando fizemos o código da classe conta, o objeto
novaconta ainda não existia. public class Conta {
A melhor maneira de se referir ao atributo é utilizar a palavra
this (“este” em português), este também é um padrão de
double saldo;
int agência;
programação importante no Java. int número;
A referência this serve para se referir aos atributos da classe String titular;
que estamos trabalhando. public void deposita(double valor) {
Por isso, não existe um this.valor, porque valor não é atributo
da classe, é apenas um variável de entrada. this.saldo = this.saldo + valor;
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 6: inclua o método saca na classe Conta
Vamos explicar porque este não é um método que retorna void
(vazio), mas retorna um valor booleano (verdadeiro ou falso). public class Conta {
Quando sacamos um valor qualquer de nossa conta no banco,
duas coisas podem acontecer.
double saldo;
int agência;
A primeira é o saque ser um sucesso, porque tinha saldo suficiente int número;
na conta. String titular;
A segunda é o saque não dar certo, porque não tinha saldo na public void deposita(double valor) {
conta. Por isso o método saca vai retornar um valor booleano.
this.saldo = this.saldo + valor;
Um valor booleano significa que será retornado true (se o saque }
der certo) ou false (se o saque der errado), e o parâmetro de
entrada valor informa ao objeto quanto será sacado da conta. public boolean saca(double valor) {
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 7: defina o que o método faz
public class Conta {
Observe que o Eclipse indica a linha do
método saca com um erro. Isso acontece double saldo;
porque você prometeu retornar um valor int agência;
booleano no método, e ainda não
int número;
String titular;
explicou como isso vai acontecer.
public void deposita(double valor) {
Vamos incluir o código do método saca.
Para definir se podemos sacar ou não o this.saldo = this.saldo + valor;
valor, vamos usar um if, que testa se o saldo
}
é maior que o valor pedido para saque. public boolean saca(double valor) {
Se for maior ou igual, diminuímos o valor do saldo e retornamos true, if(this.saldo >= valor) {
informando que deu tudo certo. this.saldo = this.saldo - valor;
return true;
Se for menor, não alteramos o saldo e retornamos false, informando que deu } else {
errado. return false;
}
}
}
1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 8: inclua um saque na classe TestaMetodo
Vamos acrescentar um saque de 15 reais:
Ao executar a classe TestaMetodo, o console public class TestaMetodo {
mostra o saldo de 50,0 e depois o saldo de
35,0, porque utilizamos antes o método saca.
public static void main(String[] args) {
Conta novaconta = new Conta();
System.out.println("O saldo da conta é "+ novaconta.saldo);
novaconta.deposita(50);
System.out.println("O saldo da conta é "+ novaconta.saldo);
novaconta.saca(1 5);
System.out.println("O saldo da conta é "+ novaconta.saldo);
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 9: usando o retorno
Observe que não utilizamos o retorno booleano
para nada. O uso das informações de retorno public class TestaMetodo {
do objeto é opcional. Vamos alterar o código
para usar o retorno. public static void main(String[] args) {
Conta novaconta = new Conta();
Agora o retorno do método aparece no
console: true. System.out.println("O saldo da conta é "+ novaconta.saldo);
novaconta.deposita(50);
System.out.println("O saldo da conta é "+ novaconta.saldo);
boolean deuCerto = novaconta.saca(1 5);
System.out.println("O saldo da conta é "+ novaconta.saldo);
System.out.println(deuCerto);
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 10: inclua o método transfere na classe Conta
public class Conta {
Quando transferimos um valor de uma conta, isso pode dar certo ou
errado, por isso o método transfere também retorna um booleano. double saldo;
int agência;
O primeiro parâmetro é valor a ser transferido. int número;
String titular;
O segundo parâmetro é a conta destino.
public void deposita(double valor) {
Observe que estamos usando pela primeira vez uma referência a um
objeto como parâmetro. É importante reforçar que não estaremos this.saldo += valor;
passando o objeto como parâmetro, apenas o endereço de memória }
para o objeto (referência). public boolean saca(double valor) {
if(this.saldo >= valor) {
A partir daqui vamos mostrar apenas o método transfere no quadro, this.saldo -= valor;
para facilitar. return true;
} else {
return false;
}
}
public boolean transfere(double valor, Conta destino) {
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 11: defina o que o método faz
Vamos incluir o código do método transfere.
Para definir se podemos transferir ou não o valor, vamos
public boolean transfere(double valor, Conta destino) {
usar um if, que testa se o saldo é maior que o valor if(this.saldo >= valor) {
pedido para transferência. this.saca(valor);
Se for maior ou igual, sacamos o valor do objeto atual e
destino.deposita(valor);
return true;
depositamos o valor no objeto destino, e retornamos } else {
true, informando que deu tudo certo. return false;
Se for menor, retornamos false, informando que a
}
}
transferência deu errado.
Observe que estamos utilizando os dois métodos
anteriores no código do método transfere.

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 12: inclua uma transferência na
classe TestaMetodo
public class TestaMetodo {
Vamos primeiro criar uma outra conta com saldo public static void main(String[] args) {
Conta novaconta = new Conta();
de 1000 reais.
System.out.println("O saldo da conta é "+ novaconta.saldo);
Agora que que temos uma outra conta com
muito dinheiro, vamos transferir 300 reais da novaconta.deposita(50);
contaDoMarco para a novaconta.
System.out.println("O saldo da conta é "+ novaconta.saldo);
Para confirmar que a transferência deu certo,
vamos apresentar o saldo da novaconta e o
novaconta.saca(1 5);
saldo da contaDoMarco. System.out.println("O saldo da conta é "+ novaconta.saldo);
Conta contaDoMarco = new Conta();
contaDoMarco.deposita(1 000);
contaDoMarco.transfere(300,novaconta);
System.out.println("O saldo da conta origem é "+ contaDoMarco.saldo);
System.out.println("O saldo da conta destino é "+ novaconta.saldo);
}
}

1 2 3 4 5 6 7 8 9 10
Comportamento (método) Implementação
Passo 13: execute e veja o resultado na console
Ao executar a classe TestaMetodo, o console mostra o saldo da conta origem com
700,0 e o saldo da conta destino com 355,0, mostrando que a transferência
funcionou.
Adicionalmente, podemos utilizar o retorno do método transfere para criar um if que
mostra uma mensagem se a transferência deu certo ou não.
Inclusive, na pergunta do if podemos colocar todo o comando
contaDoMarco.transfere(300,novaconta), já que ele retorna um booleano.

Dica: os programadores Java não costumam usar: this.saldo = this.saldo ­ valor;


Em vez disso, usamos a declaração: this.saldo ­= valor;
Significa a mesma coisa, mas economiza código, apesar de ficar mais difícil de entender para quem não está acostumado.
Outra dica: pressionando CTRL e passando o mouse sobre qualquer método ou atributo, eles se transformam em links que
levam ao código original do método ou atributo.

1 2 3 4 5 6 7 8 9 10
Documentando com Comentários
Caso de Uso
Imagine se o código que você criou será utilizado por outros
programadores no futuro. É importante que estes programadores
consigam entender o que você fez.

Para que isso ocorra, é importante documentarmos nossos


códigos, utilizando a ferramenta dos comentários.

Existe formas já consagradas para documentar código em Java.

Implementação: documente o código através de comentários na classe Conta


Estes comentários são o mínimo de documentação que precisamos, você pode
melhorar comentando mais e assim melhorando o seu código.

1 2 3 4 5 6 7 8 9 10
Encapsulamento Por que usar?
As classes podem possuir muitos atributos, estes atributos podem ser acessados
diretamente em qualquer local do código, mas esta não é uma prática public class TestaSaldoNegativo {
saudável.
Devemos tomar providência para que os atributos não possam ser acessados public static void main(String[] args) {
Conta conta = new Conta();
diretamente, tornando­os privados, e construir métodos para consultar e alterar conta.deposita(1 00);
cada um dos atributos das classes. Isto se chama encapsulamento.
System.out.println(conta.saca(1 01 ));
System.out.println(conta.saldo);
Mas antes de continuar vamos entender na prática o porquê de encapsular
todos os atributos de uma classe. Na classe TestaSaldoNegativo, criamos uma conta.saldo = conta.saldo - 1 01 ;
conta nova e depositamos 100 reais nela.
System.out.println(conta.saldo);
} }
Em seguida, tentamos sacar 101 reais da conta utilizando o método saca. Já
sabemos que o método saca testa o saldo antes, e, portanto, o método não
vai diminuir o saldo, além de retornar o valor false. Mas logo a seguir, diminuímos 101 reais diretamente do atributo saldo do
objeto conta.
Podemos perceber que isso vai funcionar perfeitamente. E o problema aí é que o atributo conta não poderia ser acessado de
qualquer ponto do programa. Tem que haver uma camada de código que verifique se aquilo que está sendo feito está correto,
de acordo com as regras do negócio que estamos modelando.

1 2 3 4 5 6 7 8 9 10
Encapsulamento Caso de Uso e
Diagrama Conceitual

Os atributos precisam estar protegidos, encapsulados.


banco
O encapsulamento é realizado em dois passos. Primeiro tornamos
todos os atributos da classe em atributos privados. Isto impedirá
que eles sejam acessíveis por outras classes. Conta
saldo
Em seguida, criamos métodos para consulta (geters) e alteração agência
número
(seters), que realizam o acesso controlado aos atributos. titular
getters
A partir do encapsulamento, as informações passam a entrar e setters
deposita
sair do objeto através de mensagens que chegam e saem dos saca
transfere
métodos. São os métodos que acessam os atributos do objeto.

1 2 3 4 5 6 7 8 9 10
Encapsulamento Implementação
Passo 1: torne os atributos da classe Conta privados utilizando private

Passo 2: inclua os métodos getters e setters

Package banco; Atributos da classe //métodos


devem ser privados public void deposita(double valor) {
public class Conta { this.saldo += valor;
}
//atributos
private double saldo; public boolean saca(double valor) {
private int agência; if(this.saldo >= valor) {
private int número; this.saldo -= valor;
Private String titular; Crie todos os return true;
métodos getters } else {
//métodos Getters return false;
public double getSaldo() { return saldo; } } }
public int getAgencia() { return agência; }
public int getNumero() { return número; } public boolean transfere(double valor, Conta destino) {
public String getTitular() { return titular; }
Crie todos os if(this.saldo >= valor) {
//métodos Setters métodos setters this.saca(valor);
public void setSaldo(double sal) { this.saldo = sal; } destino.deposita(valor);
public void setAgencia(int age) { this.agência = age;} return true;
public void setNumero(int num) { this.número = num; } } else {
public void setTitular(String tit) { this.titular = tit; } return false;
} } }

1 2 3 4 5 6 7 8 9 10
Encapsulamento Implementação
Passo 3: altere o resto do código para acessar a
classe pelos métodos getters e setters package banco; Trocando por
public class Principal { métodos setters.
Temos agora que modificar as outras classes, public static void main(String[] args) {
substituindo os acessos diretos pelos métodos de Conta conta1 = new Conta();
conta1 .setSaldo(200);
acesso. conta1 .setAgencia(30);
conta1 .setNumero(1 ); Trocando por
conta1 .setTitular("Marco"); métodos getters.
A nova classe principal ficará assim:
Conta conta2 = new Conta();
conta2.setSaldo(1 50);
conta2.setAgencia(30);
conta2.setNumero(2);
conta2.setTitular("João");
Conta conta3 = new Conta();
conta3.setSaldo(300);
conta3.setAgencia(45);
conta3.setNumero(3);
conta3.setTitular("Ana");
System.out.println("O saldo da conta 1 é "+ conta1 .getSaldo());
System.out.println("O saldo da conta 2 é "+ conta2.getSaldo());
System.out.println("O saldo da conta 3 é "+ conta3.getSaldo());
}
}

1 2 3 4 5 6 7 8 9 10
Associação Caso de Uso e
Diagrama Conceitual

Associação define um vínculo que ocorre entre classes.


banco
Se forem duas classes temos uma associação binária. É
possível termos uma associação unária, quando uma Conta Cliente
classe é vinculada a si própria. Podemos ter associações saldo nome
agência cpf
compartilhadas por mais de uma classe, conhecidas como número Possui profissão
N­ária, mas isso é mais raro. titular
getters getters
setters setters
Neste caso, vamos criar a classe Cliente, com os atributos deposita
saca
nome, cpf e profissão. transfere

A associação entre as classes Cliente e Conta será


Esta seta representa a
representada pelo atributo titular, que está na classe frase: "Cliente possui
conta".
Conta.

Este atributo antes continha uma String com o nome do


A partir de agora, não vamos mais incluir no diagrama conceitual os métodos
titular, e agora passará a ter uma classe do tipo Cliente. getters e setters, considerando que toda classe obrigatoriamente os possui.

1 2 3 4 5 6 7 8 9 10
Associação Implementação
Passo 1: crie a classe Cliente Passo 2: altere a classe Conta
Mostramos apenas as linhas que precisam ser alteradas.
Package banco; Onde o atributo titular era tipificado como String, passa
a ser do tipo Cliente, que é uma referência à um objeto.
/**
* Esta é a maneira mais comum de implementar associação.
* @author Marco Maciel
*/ Temos então um objeto como atributo de outro, neste
public class Cliente { exemplo temos uma associação entre a Classe Cliente e a
//atributos
private String nome; classe Conta. No código, um dos atributos da Conta é o
private String cpf; Cliente.
private String profissao;
//métodos Getters .
public String getNome() { return nome; }
public String getCpf() { return cpf; } public class Conta {
public String getProfissao() { return profissao; }
//atributos
//métodos Setters Private Cliente titular;
public void setNome(String nom) { this.nome = nom;}
public void setCpf(String cpf) { this.cpf = cpf; } //métodos Getters
public void setProfissao(String pro) { this.profissao = pro;} public Cliente getTitular() { return titular; }
//métodos //métodos Setters
} public void setTitular(Cliente tit) { this.titular = tit;}

1 2 3 4 5 6 7 8 9 10
Associação Implementação
Passo 3: na classe Principal, crie três
package banco; Conta conta1 = new Conta();
objetos da classe Cliente conta1 .setSaldo(200);
/** conta1 .setAgencia(30);
* conta1 .setNumero(1 );
Passo 4: na classe Principal, altere a * @author Marco Maciel conta1 .setTitular(marco);
*/
atribuição do titular na criação das Conta conta2 = new Conta();
contas public class Principal { conta2.setSaldo(1 50);
conta2.setAgencia(30);
public static void main(String[] args) { conta2.setNumero(2);
Deixamos de associar uma String e conta2.setTitular(joao);
Cliente marco = new Cliente();
passamos a associar um objeto Cliente. marco.setNome("Marco Maciel"); Conta conta3 = new Conta();
marco.setCpf("111 .111 .111 -11 "); conta3.setSaldo(300);
marco.setProfissao("Professor"); conta3.setAgencia(45);
Se não associarmos nenhum objeto Cliente conta3.setNumero(3);
a um determinado objeto Conta, o valor conta3.setTitular(ana);
Cliente joao = new Cliente();
do atributo titular ficará preenchido com joao.setNome("João Carvalho"); System.out.println("O saldo da conta 1 é "+ conta1 .getSaldo());
joao.setCpf("222.222.222-22"); System.out.println("O saldo da conta 2 é "+ conta2.getSaldo());
“null”. joao.setProfissao("Historiador"); System.out.println("O saldo da conta 3 é "+ conta3.getSaldo());
Null significa que esta referência não está }
Cliente ana = new Cliente(); }
apontando para lugar nenhum. ana.setNome("Ana Vitória");
ana.setCpf("333.333.333-33");
ana.setProfissao("Engenheira");

1 2 3 4 5 6 7 8 9 10
Construtor Caso de Uso e
Diagrama Conceitual

Quando criamos objetos, usamos o comando


“Conta conta1 = new Conta()”, e logo após, banco
informamos os dados do objeto conta1 com os
setters. O uso dos setters pode ser feito ou não,
e se não for feito, podemos ter objetos com
informações zeradas.
Conta conta1
Isto pode ser normal para o Java, mas pode saldo
saldo =
agência
representar uma violação para as regras do número
agência = 30
número = 1
negócio. A regra pode por exemplo ser: não titular
titular =
pode existir conta sem agencia e número. construtor
deposita
Para obrigar que algumas regras de negócio saca
transfere
sejam seguidas quando criamos objetos, existem
os construtores. O construtor obriga
a informar a agência
e o número.
Quando não usamos construtores, o Java já cria
escondido de nós. Mas podemos explicitá­los no
código para incluir regras de negócio.

1 2 3 4 5 6 7 8 9 10
Construtor Implementação
Passo 1: crie o construtor na classe Conta
public class Conta {
O construtor fica entre os atributos e os Getters.
Para ter certeza que está funcionando, vamos imprimir uma mensagem. //atributos
private double saldo;
private int agência;
Ao executar a classe Principal, as mensagens do método construtor private int número;
aparecem a cada vez que uma classe Conta é criada. Private String titular;
//Construtor
public Conta() {
System.out.println(“Criando uma conta agora”);
}
//métodos Getters
public double getSaldo() { return saldo; }
public int getAgencia() { return agência; }
public int getNumero() { return número; }
public String getTitular() { return titular; }

1 2 3 4 5 6 7 8 9 10
Construtor Implementação
Passo 2: inclua as regras de negócio no construtor O Java vai inclusive deixar de aceitar a criação de
objetos Conta sem nenhum parâmetro.
As regras são: não pode ter conta sem agência e
número. Temos então que corrigir a classe Principal.
Ao executar a classe Principal, as mensagens do método
//Construtor construtor aparecem a cada vez que uma classe Conta
public Conta(int age, int num) { é criada.
this.agência = age;
this.número = num;
System.out.println(“Criando a conta ”+this.número+” na agência”
+ this.agência); Conta conta1 = new Conta(30,1 );
} conta1 .setSaldo(200);
conta1 .setTitular(marco);
A partir de agora, só podemos criar uma Conta se Conta conta2 = new Conta(30,2);
informarmos o número e a agência.
conta2.setSaldo(1 50);
conta2.setTitular(joao);
Conta conta3 = new Conta(45,3);
conta3.setSaldo(300);
conta3.setTitular(ana);

1 2 3 4 5 6 7 8 9 10
Construtor Implementação
Passo 3: avalie os setters
A regra de negócio que nos levou a implementação do construtor diz: não pode haver uma Conta sem agência e
número. E isto foi implementado com sucesso.
Uma outra regra de negócio que deriva da anterior é: uma Conta não pode ter seu número e agência mudados
depois da criação. Este tipo de atributo é chamado de atributo imutável.
No mundo real isso é verdade, não podemos mudar estes dados de uma Conta já criada. Temos que criar uma nova
conta.
Isto significa que os métodos setNúmero e setAgência não podem existir, porque estão violando esta regra de
negócio, já que permite a mudança destes atributos a qualquer momento.
Vamos então eliminá­los da classe Conta, aproximando a implementação do sistema do mundo real.
Nossa nova classe Conta está a seguir:

1 2 3 4 5 6 7 8 9 10
Construtor Implementação

Nossa nova classe Conta está a seguir:

Package banco; //métodos Getters


public double getSaldo() { return saldo; }
/** public int getAgencia() { return agência; }
* public int getNumero() { return número; }
* @author Marco Maciel public String getTitular() { return titular; }
*/
//métodos Setters
public class Conta { public void setSaldo(double sal) { this.saldo = sal; }
//atributos public void setTitular(String tit) { this.titular = tit; }
private double saldo;
private int agência; //métodos
private int número; public void deposita(double valor) {
Private String titular; this.saldo += valor;
}
//Construtor
public Conta(int age, int num) { public boolean saca(double valor) {
this.agência = age; if(this.saldo >= valor) {
this.número = num; this.saldo -= valor;
System.out.println(“Criando a conta ”+this.número+” na agência return true;
”+this.agência);} } else {
return false; } }

1 2 3 4 5 6 7 8 9 10
Construtor Implementação

Veja que a classe Conta está ficando bem grande.


public boolean transfere(double valor, Conta destino) { Uma forma de facilitar a navegação pelo código é
if(this.saldo >= valor) { utilizar a janela Outline.
this.saca(valor); Para ativá­la, cliquem em
destino.deposita(valor);
return true; Window ­> Show View ­> Outline
} else {
return false; Podemos clicar em qualquer
} elemento da lista, que o Eclipse
}
} nos leva diretamente ao código
correspondente.

1 2 3 4 5 6 7 8 9 10
Atributo Estático Caso de Uso e
Diagrama Conceitual

Precisamos de saber quantas contas o banco


possui. banco

Esta é uma informação da classe Conta. Mas


não é uma informação que pertence a cada O atributo estático
existe na classe,
objeto Conta. mas não nos objetos
criados.
Conta conta1
Diferente do saldo da conta, quando cada saldo
saldo =
agência
objeto tem o seu, a informação de quantas número
agência = 30
número = 1
contas existem é uma informação geral, da titular
titular =
TotalContas
classe Conta. deposita
saca
transfere
Este tipo de atributo é conhecido como atributo getTotalContas
estático. O get para um
atributo estático
também é estático.

1 2 3 4 5 6 7 8 9 10
Atributo Estático Implementação
Passo 1: inclua o atributo estático TotalContas na
classe Conta public class Conta {
//atributos
private double saldo;
Observe algumas coisas no código: private int agência;
• O Eclipse coloca as variáveis estáticas em itálico, private int número; Toda vez que criamos uma
para diferencia­las das outras.
private Cliente titular; nova conta, o construtor
private static int TotalContas; adiciona 1 à variável
• Não podemos utilizar this para variáveis estáticas. TotalContas.
Isto porque a variável TotalContas não pertence a //Construtor
public Conta(int age, int num) {
nenhum objeto. Em vez disso temos que nos referir this.agência = age;
diretamente à classe. this.número = num;
• Como TotalContas é private, temos que criar um Conta.TotalContas ++;
System.out.println("Conta: "+this.número+" Agência: "+this.agência);
método get. System.out.println("Quantidade de Contas: "+Conta.TotalContas);
• A informação TotalContas não é de um objeto }
conta em especial, mas da classe como um todo, //métodos Getters
portanto o método também deve ser estático. public double getSaldo() { return saldo;}
• Para garantir encapsulamento, não teremos método public int getAgencia() { return agência;}
public int getNumero() { return número;}
set para TotalContas. Assim, apenas o construtor pode public Cliente getTitular() { return titular;}
alterar TotalContas. public static int getTotalContas() { return TotalContas;}

1 2 3 4 5 6 7 8 9 10
Atributo Estático Implementação
Passo 2: execute a classe Principal
Ao executar a classe Principal, as mensagens do método construtor aparecem a cada vez que uma classe Conta
é criada, informando sempre quantas contas o banco possui.

1 2 3 4 5 6 7 8 9 10
Herança Caso de Uso e
Diagrama Conceitual

O banco pretende agora ter as informações sobre seus


funcionários. Os atributos do Funcionário são nome, cpf e banco
salário.

Acontece que já temos a classe Cliente, com os atributos Pessoa


nome, cpf e profissão. Perceba que alguns atributos se nome
repetem nas classes Funcionário e Cliente. cpf

Vamos criar uma classe chamada Pessoa, com os atributos


nome e cpf. Esta classe Pessoa é chamada de
superclasse. As classes Funcionário e Cliente serão
subclasses de Pessoa.
Cliente Funcionário
Isso significa que as subclasses Funcionário e Cliente
herdarão todos os atributos e métodos criados para a profissão salário
superclasse pessoa.

Uma coisa importante de avisar neste momento é: existe calcComissão


uma coisa que a subclasse não herda da superclasse,
que são os construtores. Quando fazemos uma classe filho,
temos que reescrever o construtor do filho.

1 2 3 4 5 6 7 8 9 10
Herança Implementação
Passo 1: crie a classe Pessoa
Para facilitar, vamos copiar a classe Cliente, clicando com o botão direito do mouse na
classe cliente.
No menu que aparece, escolha “copy”. Depois entre
de novo e clique em “paste”. Também funciona se
você marcar a classe Cliente e dar “Ctrl+C” e “Ctrl+V”.
Na janela que aparece, troque o nome para Pessoa.

A nova classe já vai ter em seu código, a palavra


Cliente trocada por Pessoa.
Retire as referências ao atributo profissão da
classe Pessoa.

1 2 3 4 5 6 7 8 9 10
Herança Implementação
Passo 2: altere a classe Pessoa
Package banco;
Temos então uma superclasse chamada Pessoa.
/**
Observe que nada indica que Pessoa é uma superclasse. *
Isto ficará visível ao criarmos uma das subclasses.
* @author Marco Maciel
*/
public class Pessoa {
//atributos
private String nome;
private String cpf;
//métodos Getters
public String getNome() { return nome; }
public String getCpf() { return cpf; }
//métodos Setters
public void setNome(String nom) { this.nome = nom;}
public void setCpf(String cpf) { this.cpf = cpf; }
//métodos
}

1 2 3 4 5 6 7 8 9 10
Herança Implementação
Passo 3: crie a classe Funcionario
package banco;
A classe Funcionário será criada como subclasse de Pessoa.
/**
Isto é informado logo após o nome da classe, usando a palavra *
extends. * @author Marco Maciel
*/
Funcionario extends Pessoa significa que Funcionário também é public class Funcionario extends Pessoa {
uma pessoa.
//atributos
Por consequência, tudo que for definido para Pessoa valerá private double salario;
também para Funcionario.
//métodos Getters
Ao mesmo tempo, a classe Funcionario possui atributos e métodos public double getSalario() { return salario; }
que são específicos para ela. //métodos Setters
Uma pessoa tem nome e CPF, mas não tem salário. Além disso o public void setSalario(double sal) { this.salario = sal;}
método que calcula comissão só faz sentido para o funcionário. //métodos
Uma pessoa qualquer não tem comissão. public double calcComissão() {
return this.getSalario() * 0.1 ;
}
}

1 2 3 4 5 6 7 8 9 10
Herança Implementação
Passo 4: teste a criação de um objeto funcionario
Inclua no final da classe Principal a criação do funcionário Lucas, e depois calcule a comissão dele.

Atributos que vem da classe Funcionario lucas = new Funcionario(); Atributo que vem da classe
Pessoa. lucas.setNome("Lucas Guerrini"); Funcionario.
lucas.setCpf("444.444.444-44");
lucas.setSalario(1 350.00);
System.out.println("\n");
System.out.println("Funcionario "+ lucas.getNome()+" tem comissão de "+ lucas.calcComissão());

Veja que o objeto lucas permite receber os atributos nome e cpf. Isso porque lucas também é um objeto da classe
Pessoa. Mas também podemos informar o atributo salário, porque lucas também é um objeto da classe Funcionario.
Veja que ainda podemos calcular a comissão de Lucas, que é um método que só funciona para a classe Funcionario.

1 2 3 4 5 6 7 8 9 10
Herança Implementação
Passo 5: altere a classe Cliente para que ela seja subclasse
de Pessoa package banco;
/**
A orientação a objetos nos permite um reaproveitamento máximo *
de código. E isso fica claro neste momento, já que um cliente * @author Marco Maciel
também é uma pessoa. */
Portanto, a classe Cliente também deve herdar tudo da classe public class Cliente extends Pessoa {
Pessoa. Vamos alterar a classe Cliente. //atributos
private String profissao;
Inclua na frente do nome da classe Cliente a indicação “extends
Pessoa”. //métodos Getters
public String getProfissao() { return profissao;}
Elimine todas as referências aos atributos nome e cpf.
//métodos Setters
Deixe apenas aquilo que é específico ao Cliente, ou seja, a public void setProfissao(String pro) { this.profissao = pro;}
profissão. //métodos
}
Podemos executar a classe Principal sem fazer nenhuma alteração
no código. As referências à classe Cliente continuam funcionando
normalmente.

1 2 3 4 5 6 7 8 9 10
Reescrita (Sobrescrita) Caso de Uso e
Diagrama Conceitual

Temos as classes Pessoa, Funcionario e Cliente. Vamos


fazer um método chamado apresentação que vai mostrar banco
quem é a Pessoa ou Funcionario ou Cliente.

A questão é que esta apresentação deverá variar, Pessoa


dependendo da Classe. Se for um funcionário tem que nome
cpf
mostrar o nome e o salário, se for um Cliente tem que
mostrar o nome e a profissão, e se for Pessoa não precisa
apresentação
mostrar nada além do nome.

Para isso vamos mostrar o conceito de reescrita de


método.
Cliente Funcionário
profissão salário

apresentação calcComissão
apresentação

1 2 3 4 5 6 7 8 9 10
Reescrita (Sobrescrita) Implementação
Passo 1: crie o método apresentação na classe Pessoa
package banco;
//métodos /**
public void apresentação() { *
System.out.println("Sou apenas uma pessoa e me chamo "+ this.getNome()); * @author Marco Maciel
*/
} public class TestaReescrita {
public static void main(String[] args) {
Passo 2: crie a classe TestaReescrita
Pessoa marco = new Pessoa();
marco.setNome("Marco Maciel");
Passo 3: crie o objeto “marco” a partir da classe Pessoa marco.setCpf("111 .111 .111 -11 ");
marco.apresentação();
Passo 4: apresente marco através do método apresentação System.out.println("\n");
Passo 5: execute TestaReescrita e veja o resultado }
}

1 2 3 4 5 6 7 8 9 10
Reescrita (Sobrescrita) Implementação
Passo 6: crie o método apresentação na classe Cliente
Package banco;
//métodos /**
public void apresentação() { *
System.out.println("Sou um cliente e me chamo "+ this.nome); * @author Marco Maciel
System.out.println("Minha profissão é "+ this.getProfissao()); */
} public class Pessoa {
//atributos
protected String nome;
O código acima não será aceito pelo Java. Isto porque estamos tentando protected String cpf;
acessar o nome do Cliente.
//métodos Getters
A classe Cliente não tem atributo nome, este atributo está na superclasse Pessoa. public String getNome() { return nome; }
Este atributo na classe Pessoa é Private, por isso está dando erro. Estamos public String getCpf() { return cpf; }
enfrentando uma questão de visibilidade. //métodos Setters
Podíamos alterar o atributo nome para public, mas aí todo o sistema teria public void setNome(String nom) { this.nome = nom;}
acesso ao atributo, e isso fere a regra do encapsulamento.
public void setCpf(String cpf) { this.cpf = cpf; }
Existe um meio termo que resolve a questão: a opção protected. //métodos
}
Esta opção é um meio termo entre public e private. O atributo fica público para
os filhos da classe, mas fica privado para o resto do sistema. Mas ainda falta um
detalhe.

1 2 3 4 5 6 7 8 9 10
Reescrita (Sobrescrita) Implementação
Passo 7: não use this, use super

Quando estamos codificando uma subclasse e referimos a um atributo da superclasse, é importante que isto fique
documentado, por isso em vez de this usamos super.

//métodos
public void apresentação() {
System.out.println("Sou um cliente e me chamo "+ super.nome);
System.out.println("Minha profissão é "+ this.getProfissao());
}

Tudo isso foi apenas para explicar a questão da visibilidade, que resolvemos com as palavras reservadas protected e
super. Poderíamos ter apenas utilizado o método getNome.

//métodos
public void apresentação() {
System.out.println("Sou um cliente e me chamo "+ super.getNome();
System.out.println("Minha profissão é "+ this.getProfissao());
}

1 2 3 4 5 6 7 8 9 10
Reescrita (Sobrescrita) Implementação
Passo 8: crie o objeto “joao” a partir da classe Cliente
package banco;
Passo 9: apresente o joao através do método apresentação public class TestaReescrita {
Passo 10: execute TestaReescrita e veja o resultado public static void main(String[] args) {
Pessoa marco = new Pessoa();
marco.setNome("Marco Maciel");
marco.setCpf("111 .111 .111 -11 ");
marco.apresentação();
System.out.println("\n");
Cliente joao = new Cliente();
joao.setNome("João Carvalho");
joao.setCpf("222.222.222-22");
joao.setProfissao("Historiador");
joao.apresentação();
System.out.println("\n");
}
}

1 2 3 4 5 6 7 8 9 10
Reescrita (Sobrescrita) Implementação
Passo 11: crie o método apresentação na classe Funcionario package banco;
public class TestaReescrita {
//métodos public static void main(String[] args) {
public void apresentação() {
System.out.println("Sou um funcionário e me chamo "+ super.nome); Pessoa marco = new Pessoa();
System.out.println("Meu salário é "+ this.getSalario()); marco.setNome("Marco Maciel");
marco.setCpf("111 .111 .111 -11 ");
}
marco.apresentação();
System.out.println("\n");
Passo 12: crie o objeto “ana” a Cliente joao = new Cliente();
joao.setNome("João Carvalho");
partir da classe Funcionario joao.setCpf("222.222.222-22");
joao.setProfissao("Historiador");
joao.apresentação();
Passo 13: apresente a ana System.out.println("\n");
através do método apresentação Funcionario ana = new Funcionario();
ana.setNome("Ana Vitória");
ana.setCpf("333.333.333-33");
ana.setSalario(1 000);
Passo 14: execute TestaReescrita
ana.apresentação();
e veja o resultado System.out.println("\n");
}
}

1 2 3 4 5 6 7 8 9 10
Reescrita (Sobrescrita) Implementação
Passo 15: reflita comigo

Apresentamos na prática o conceito de reescrita ou sobrescrita.


Observe que as chamadas para o método apresentação são exatamente iguais.
Porém, quando estamos falando de objetos filhos, o próprio Java se encarrega de usar os métodos criados
especificamente para as subclasses.
Isto nos permite redefinir um comportamento previsto na superclasse, tornando­o específico para uma subclasse.

1 2 3 4 5 6 7 8 9 10
Sobrecarga Caso de Uso e
Diagrama Conceitual

Temos um método que calcula a comissão, mas este


método calcula uma porcentagem fixa de 10% de banco
comissão.

Precisamos ter também um outro método que receba uma


porcentagem como parâmetro, mas o nome dos dois
métodos tem que ser o mesmo. Funcionario
salario
Para isso vamos mostrar o conceito de sobrecarga de
método.
calcComissao
calcComissao(x)
apresentação

1 2 3 4 5 6 7 8 9 10
Sobrecarga Implementação
Passo 1: crie um novo método calcComissao na classe Funcionário
Este novo método receberá a porcentagem da
//métodos comissão.
public double calcComissão() { Observe que o Java não dá erro. Como este o
return this.getSalario() * 0.1 ; primeiro CalcComissão não tinha parâmetros de
}
entrada e este segundo CalcComissão possui um
public double calcComissão(double porcentagem) { parâmetro double, o Java entende que estamos
return this.getSalario() * porcentagem;
} realizando uma supercarga.
public void apresentação() { Podemos criar quantos métodos CalcComissão
System.out.println("Sou um funcionário e me chamo "+ super.nome); quisermos, o importante é que cada um deles
System.out.println("Meu salário é "+ this.getSalario()); tenha parâmetros de entrada diferentes.
}
O Java vai saber qual método deve ser
executado, de acordo com os parâmetros que
forem passados.

1 2 3 4 5 6 7 8 9 10
Sobrecarga Implementação
Passo 2: crie a classe TestaSobrecarga Passo 3: execute TestaSobrecarga e veja o
resultado no console
package banco;
public class TestaSobrescrita {
public static void main(String[] args) {
Funcionario ana = new Funcionario();
ana.setNome("Ana Vitória");
ana.setCpf("333.333.333-33");
ana.setSalario(1 000);
System.out.println("A comissão da Ana pode ser "+ana.calcComissão());
System.out.println("Ou pode ser "+ana.calcComissão(0.20));
System.out.println("Depende de qual calcComissão for chamado");
}
}

1 2 3 4 5 6 7 8 9 10
Polimorfismo Caso de Uso e
Diagrama Conceitual

Os dois conceitos apresentados anteriormente


banco
(Sobrescrita e Sobrecarga) podem ser agrupados
com o nome de Polimorfismo. Pessoa
Polimorfismo acontece quando temos mais de um nome
cpf
método, em uma mesma classe, com o mesmo nome,
contanto que ele possua uma passagem de
apresentação
parâmetros diferente, ou quando um método mais
específico sobrescreve o Método de uma
superclasse.
O método apresentação no exemplo sofre Cliente Funcionario
sobrescrita, e o método calcComissao é um exemplo profissão salario
de sobrecarga.
apresentação calcComissao
calcComissao(x)
apresentação

1 2 3 4 5 6 7 8 9 10
Classe Abstrata Caso de Uso e
Diagrama Conceitual

O banco controla em seu sistema funcionários e clientes.


banco
Este controle foi implementado de uma forma que
podemos ter pessoas também, que não são nem
funcionários nem clientes. Pessoa
nome
cpf
Veja que não há nenhuma razão para o banco guardar
pessoas em sua base de dados que não sejam
apresentação
funcionários ou clientes.

Isso significa que a classe Pessoa não deveria poder criar


objetos pessoa. Este tipo de classe que não pode ser
Cliente Funcionario
instanciada diretamente é chamado de classe abstrata.
profissão salario

Elas servem como modelo para criar subclasses.


calcComissao
No diagrama conceitual a classe abstrata exibe seu apresentação
calcComissao(x)
nome em itálico. apresentação

1 2 3 4 5 6 7 8 9 10
Classe Abstrata Implementação
Passo 1: torne a classe Pessoa uma classe abstrata
Package banco;
Para tornar abstrata a classe Pessoa, basta incluir a
palavra abstract na primeira linha da classe. public abstract class Pessoa {
//atributos
private String nome;
Passo 2: corrija a classe TestaReescrita private String cpf;
Ao tornar Pessoa uma classe abstrata, o código da //métodos Getters
classe TestaReescrita passa a dar erro quando public String getNome() { return nome; }
public String getCpf() { return cpf; }
tentamos criar o objeto marco.
//métodos Setters
Ou excluímos esta parte do código, já que não existe public void setNome(String nom) { this.nome = nom;}
objetos da classe Pessoa, ou precisamos trocar a public void setCpf(String cpf) { this.cpf = cpf; }
classe do marco para funcionário ou Cliente. //métodos
public void apresentação() {
System.out.println("Sou apenas uma pessoa e me chamo "+
this.getNome());
Pessoa marco = new Pessoa();
marco.setNome("Marco Maciel"); }
marco.setCpf("111 .111 .111 -11 "); }

1 2 3 4 5 6 7 8 9 10
Método Abstrato Caso de Uso e
Diagrama Conceitual

A classe Pessoa possui um método apresentação que


nunca vai ser executado, já que não existem objetos da banco
classe abstrata Pessoa. Este método apresentação foi
implementado nas classes Funcionário e Cliente.
Pessoa
Podemos apagar o método apresentação da classe nome
cpf
pessoa, mas precisamos garantir que todas as futuras
subclasses que serão criadas implementem o método
apresentação
apresentação. Para garantir isso basta tornar o método
abstract.

No diagrama conceitual o método abstracto exibe seu


Cliente Funcionario
nome em itálico.
profissão salario

apresentação calcComissao
calcComissao(x)
apresentação

1 2 3 4 5 6 7 8 9 10
Método Abstrato Implementação
Passo 1: torne o método apresentação da classe Pessoa
um método abstrato Package banco;
public abstract class Pessoa {
Para tornar abstrato o método apresentação da classe //atributos
Pessoa, basta incluir a palavra abstract na definição do private String nome;
private String cpf;
método.
//métodos Getters
O código que havia dentro do método apresentação deve public String getNome() { return nome; }
ser deletado, e o abre e fecha chaves substituído por um public String getCpf() { return cpf; }
ponto e vírgula. //métodos Setters
Isto vai obrigar todas as subclasses de Pessoa a terem o public void setNome(String nom) { this.nome = nom;}
public void setCpf(String cpf) { this.cpf = cpf; }
método apresentação.
//métodos
public abstract void apresentação();
Passo 2: exclua o método apresentação da classe Cliente
}
Veremos que o Java não permite à classe Cliente existir sem
que haja a implementação do método apresentação.

1 2 3 4 5 6 7 8 9 10
Interface Caso de Uso
O banco necessita a implementação de uma checagem
de senha, e ao analisar o negócio, percebeu­se que esta
checagem serviria para a Conta e também para o
Cliente.

Não devemos implementar na classe ChecaSenha dois


métodos para fazer a mesma coisa, só porque temos duas
classes que precisam de checagem. O ideal é usarmos
interfaces, que são classes totalmente abstratas, que
funcionam como contratos.

As classes que precisarem utilizar a checagem deverão


contratar o serviço da interface, que vamos chamar de
Checável.

1 2 3 4 5 6 7 8 9 10
Interface Diagrama Conceitual

banco
ChecaSenha <<interface>>
Checavel Pessoa
Calcular confereSenha nome
cpf
checagem

apresentação

Conta
saldo Cliente Funcionario
agência
número profissão salario
titular
TotalContas
Possui
deposita apresentação calcComissao
saca calcComissao(x)
transfere apresentação
getTotalContas

1 2 3 4 5 6 7 8 9 10
Interface Implementação
Passo 1: crie a interface que será contratada pelas classes
Clique com o botão direito do mouse na pasta src, depois clique em
new ­> Interface. Informe o nome da interface e clique finish.

1 2 3 4 5 6 7 8 9 10
Interface Implementação
Passo 2: defina os serviços que a
interface vai prover package banco; package banco;
No caso o método confereSenha é public interface Checavel { public interface Checavel {
definido como sendo “public abstract”. public abstract boolean confereSenha(); boolean confereSenha();
Mas como tudo em uma interface é } }
abstrato, o Java aceita que não se
defina “public abstract”. Ele já vai
considerar assim por se tratar de uma
interface.
package banco;
Passo 3: crie a classe ChecaSenha
public class ChecaSenha {
É esta classe que vai realizar o serviço da interface que vai ser
private boolean resultado;
contratado pelas classes Conta e Cliente.
public void confereSenha(Checavel c) {
this.resultado = c.confereSenha();
}
}

1 2 3 4 5 6 7 8 9 10
Interface Implementação
Passo 4: faça as classes Conta e Cliente contratarem a interface
Checavel public class Conta implements Checavel {
Quando isto é feito, o Java já avisa que as classes Conta e Cliente public class Cliente extends Pessoa implements Checavel {
tem que ter um método confereSenha. Isto porque essas classes
contrataram a interface Checavel.

Passo 5: inclua o código do método confereSenha nas classes


Conta e Cliente public boolean confereSenha() {
return false;
Para facilitar o teste, faça o método retornar false na classe Conta e
}
true na classe Cliente.

1 2 3 4 5 6 7 8 9 10
Interface Implementação
Passo 6: faça o teste do método confereSenha no final do código da classe Principal

System.out.println("Resposta da conferência de senha para a Conta 45 "+ conta3.confereSenha());


System.out.println("Resposta da conferência de senha para o Cliente João "+ joao.confereSenha());

Ao executar a classe Principal, vemos o resultado no console.


Observe que confereSenha é executado tanto pela classe
Conta como pela classe Cliente, porque as duas contrataram
a interface Checavel.

1 2 3 4 5 6 7 8 9 10
Finalizando
Quando usar classe abstrata e quando usar interface Herança permite reutilização de código e polimorfismo
Quando a abstração que precisar ser criada for um Se quisermos implementar apenas a reutilização de
conceito, ou seja, algo que possa ser refinado e código, podemos usar composição de classes
especializado, deve­se utilizar uma classe abstrata. (associação)
Quando a abstração é um comportamento, ou seja, algo Se quiser implementar apenas polimorfismo, podemos usar
que uma classe deve saber fazer, então a melhor interface.
solução é a criação de uma interface.
Imagine um jogo no qual existem naves que se movem. Se
sua abstração representa uma nave, então você está
representando um conceito e deve utilizar uma classe
abstrata. Por outro lado, se sua abstração representa
algo que se move, então o que está sendo abstraído é
um comportamento e a melhor solução é usar uma
interface.

1 2 3 4 5 6 7 8 9 10
Referências
Livro ­ Java como programar ­ Deitel
Curso Alura ­ Java OO: Introdução à Orientação a Objetos
Curso Alura ­ Java Polimorfismo: Entenda herança e interfaces

Krita Inkscape Scribus Pexels Gimp Synfig Audacity Kdenlive

1 2 3 4 5 6 7 8 9 10
Só mais uma coisa...

@laertecoutinho1

O professor não é dono do saber.


O professor é um organizador de conhecimento, que tem a experiência adequada
para selecionar o que é relevante neste mar infinito de informação.

1 2 3 4 5 6 7 8 9 10
marco@iftm.edu.br

@marcomacielpro Produzido em 2022

Você também pode gostar