Livro 01 - Introdução A Orientação A Objetos
Livro 01 - Introdução A Orientação A Objetos
Livro 01 - Introdução A Orientação A Objetos
LIVRO 01
Introdução a Orientação a Objetos
Sumário
1 2 3 4 5 6 7 8 9 10
Projeto Caso de Uso e Diagrama Conceitual
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.
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
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
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 tratase 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
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
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.
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.
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.
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”
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
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
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);
}
}
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.
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.
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, tornandoos 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
1 2 3 4 5 6 7 8 9 10
Encapsulamento Implementação
Passo 1: torne os atributos da classe Conta privados utilizando private
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
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
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
1 2 3 4 5 6 7 8 9 10
Construtor Implementação
1 2 3 4 5 6 7 8 9 10
Atributo Estático Caso de Uso e
Diagrama Conceitual
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 diferencialas 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
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.
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
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
1 2 3 4 5 6 7 8 9 10
Sobrecarga Caso de Uso e
Diagrama Conceitual
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
1 2 3 4 5 6 7 8 9 10
Classe Abstrata Caso de Uso e
Diagrama Conceitual
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
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, percebeuse que esta
checagem serviria para a Conta e também para o
Cliente.
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.
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
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, devese 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
1 2 3 4 5 6 7 8 9 10
Só mais uma coisa...
@laertecoutinho1
1 2 3 4 5 6 7 8 9 10
[email protected]