Orientação a objetos

Usando objetos

Objetivos

  Introduzir a Orientação a Objeto (OO) e o uso de objetos:

    Objetos do mundo real

    Comportamento dos objetos do mundo real

    Referências a objetos

    Encapsulamento

    Interfaces de objetos

    Identidade de objetos

    Estado de um objeto (atributos e sua persistência)

    Classificação dos objetos

    Comportamento definido pela classe e pelos métodos

    Métodos como envio de mensagens

    Reificação e objetos de software "vivos"

    Tratamento de erros com exceções

Introdução a orientação a objetos (OO)

  Pode-se pensar sobre o mundo real como uma coleção de objetos relacionados

  Exemplos de objetos do mundo bancário:

    Contas correntes

    Contas de poupança

    Clientes

    Caixas

    Agências

    Cheques

    Extratos

  Objetos podem ser agrupados em classes

    Conta corrente

    Conta de poupança

    Cliente

    Caixa

    Agência

    Cheque

    Extratos

  Observe que existem várias Contas correntes de uma mesma classe "Conta corrente". A diferença entre classe e objeto:

    "Classe" é um gabarito (como a planta de uma casa)

    "Objeto" é a concretização do gabarito (casas feitas a partir da mesma planta)

Casas (objetos)

 
 


Planta (classe)

 
                                                       MCj04381830000[1]

                                                               MCj04338560000[1]

                                                     MCj04316270000[1]

·    Objetos de uma certa classe têm atributos

°      Uma Conta tem um número, um saldo, um histórico de transações

°      Um Cliente tem um nome, um endereço

°      Um Cheque tem um valor

·    Objetos de uma mesma classe têm um mesmo comportamento

°      Clientes entram numa agência

°      Clientes fazem depósitos e saques

°      Clientes emitem cheques

·    Certos objetos não têm comportamento

°      Contas não são vivas: não "fazem" nada

·    Objetos podem estar relacionados

°      Um cliente possui várias Contas

·    Podemos usar objetos ao fazer software também

·    Há várias vantagens de fazer isso

°      É um pouco difícil entender todas as vantagens de OO agora

°      Mencionemos apenas duas:

i)   É mais fácil conversar com o cliente que pediu o software se falarmos com objetos que existem no mundo dele (o mundo do software fica mais perto do mundo real)

ii)          O software feito com OO pode ser feito com maior qualidade e pode ser mais fácil de escrever e, principalmente, alterar no futuro

·    Esses pontos não ficarão claros na disciplina de Programação 2 mas certamente o ficarão adiante no curso

O Primeiro Programa OO: Instanciação e Uso de Objetos

·    Nesta seção, queremos aprender a usar objetos e não a criá-los ainda

·    Problema a resolver: modelar Contas bancárias simples e fazer algumas manipulações

·    Usaremos uma classe chamada ContaSimples que já existe na biblioteca de classes escritas pelo professor Jacques

°      Esta biblioteca se chama p1.aplic.banco e serve para escrever aplicações simples do mundo bancário

°      Adiante nesta disciplina, veremos as implementações dessas classes

package p2.exemplos;

 

/*

 * Movimentação simples de uma conta bancária

 */

 

// Precisaremos usar classes já prontas no programa

// Aqui, estamos trazendo essas classes para "dentro" do nosso programa

import p1.aplic.banco.*; // para poder manusear contas bancárias

 

// Programa Banco1

public class Banco1 {

 

   // Um programa sempre tem um "método" main que é onde começa a execução

   public static void main(String args[]) {

 

      // Abra uma conta de número 1 para João com CPF 309140605-06

      // A conta será "referenciada" com a variável umaConta

      ContaSimples umaConta = new ContaSimples("Joao", "30914060506", 1);

     

      // Nesta conta, deposite R$1000,00

      umaConta.depositar(1000.0);

 

      // Imprima o saldo da conta de João

      double saldo = umaConta.getSaldo();

      System.out.print("Saldo da conta de Joao antes do saque: ");

      System.out.println(saldo);

 

      // Saque R$300,00 desta conta

      umaConta.sacar(300.0);

 

      // Imprima o objeto umaConta

      System.out.println(umaConta);

 

      // Imprima o saldo da conta de João

      System.out.println("Saldo da conta de Joao depois do saque: "

            + umaConta.getSaldo());

 

   } // fim do método main

} // fim da classe Banco1

·    A saída deste programa é:

Saldo da conta de Joao antes do saque: 1000.0

ContaSimples numero 1, titular Joao, data 26/02/2009, saldo R$700,00

Saldo da conta de Joao depois do saque: 700.0

·    A linha com "import" é usada para dizer ao compilador Java que estaremos usando classes do "pacote" p1.aplic.banco

·    Um objeto é criado com a palavra new, especificando sua classe

°      Diz-se "chamamos o construtor da classe"

°      A operação também se chama instanciar o objeto

·    No caso da classe ContaSimples, o construtor tem 3 parâmetros que são o valor de certos atributos do objeto (nome do titular, CPF do titular, número da conta)

·    Observe que não temos classe Cliente para representar o titular da conta

°      A conta em si assume os atributos do titular

·    A variável umaConta é do tipo da classe ContaSimples e armazena uma referência ao objeto

MCj02337650000[1]

°      É como se o objeto fosse uma pipa e a referência fosse uma linha amarrada à pipa

°      Ou como se o objeto fosse uma televisão e a referência fosse o seu controle remoto

·    É semelhante a ponteiros em outras linguagens

 

·    MMj03369130000[1]Um objeto existe enquanto houver pelo menos uma referência a ele

·    Depois que não houver mais referências, o objeto some (que nem a pipa sem linha!)

·    No programa, estamos vendo chamadas a 4 comportamentos do objeto umaConta

°      depositar(...)

°      sacar(...)

°      getSaldo()

°      toString()

·    A sintaxe umaConta.depositar(1000.0) significa que estamos chamado o método depositar() do objeto umaConta

°      Um método é como um sub-programa, subrotina ou função de outras linguagens

°      Também se fala que estamos enviando a mensagem "depositar" para o objeto "umaConta"

·    Certos métodos podem ter parâmetros e outros não

·    Podemos imprimir um objeto como um todo!

System.out.println(umaConta);

·    Isto é equivalente a:

System.out.println(umaConta.toString());

·    …porque toda classe tem um método toString que retorna uma representação do objeto e dos seus atributos como String

°      Pergunta: qual é o String retornado por umaConta.toString()?

°      A partir deste String, você pode identificar um provável atributo de uma ContaSimples que não vimos até agora nem informamos no construtor?

·    Objetos oferecem serviços

·    Um dos seus objetivos como bom programador é produzir e/ou localizar os objetos ideais para resolver o seu problema

·    Java oferece um conjunto grande de classes (que são fôrmas para se criar objetos e usá-los)

°      Além disso, você pode escrever novos tipos de dados e estender a linguagem Java

Encapsulamento

·    Muito importante: conseguimos usar objetos da classe ContaSimples sem saber nada sobre como ContaSimples está escrita em Java!

°      Isso se chama Ocultação de Informação e é muito importante na programação

°      É a forma básica de lidar com a complexidade dos programas

·    Também podemos dizer que a Classe ContaSimples encapsula dados e comportamento em cima desses dados

°      Os dados são os atributos escondidos de nós (saldo, histórico de transações, dados do titular, …)

°      O comportamento são os métodos que podemos chamar para manipular o objeto, i.e., as mensagens que podemos mandar para os objetos

°      Só podemos "mexer" no objeto através de seus métodos

 

 

 

 

 


·    Portanto, vê-se que classes como ContaSimples têm comportamento

°      Mais precisamente, os objetos dessa classe é que têm comportamento definido pela classe

·    Podemos ver uma definição mais completa do comportamento da classe ContaSimples aqui

publicoxprivado.bmp

 

 

Próximo programa: Identidade de objetos

  Pense sobre a implementação do seguinte programa, dado em pseudo-código

Programa Banco2

    Abra uma conta de número 1 para João com CPF 309140605-06

    Nesta conta, deposite R$1000,00

    Abra uma conta de número 2 para Ana com CPF 123456789-01

    Transfira R$400,00 da conta de João para a conta de Ana

    Imprima o saldo da conta de João

    Imprima o saldo da conta de Ana

  A solução em Java está a seguir:

package p2.examples;

 

/*

 * Movimentação simples de duas contas bancárias

 */

 

import p1.aplic.banco.*; // para poder manusear contas bancárias

 

public class Banco2 {

   public static void main(String args[]) {

      // Abra uma conta de número 1 para João com CPF 309140605-06

      // A conta será "referenciada" com a variável umaConta

      ContaSimples umaConta = new ContaSimples("Joao", "30914060506", 1);

      // Nesta conta, deposite R$1000,00

      umaConta.depositar(1000.0);

 

      // Abra uma conta de número 2 para Ana com CPF 123456789-01

      // A conta será "referenciada" com a variável outraConta

      ContaSimples outraConta = new ContaSimples("Ana", "12345678901", 2);

      // Transfira R$400,00 da conta de João para a conta de Ana

      umaConta.transferir(outraConta, 400.0);

 

      // Imprima o saldo da conta de João

      double saldo = umaConta.getSaldo();

      System.out.print("Saldo da conta de Joao: ");

      System.out.println(saldo);

 

      // Imprima o saldo da conta de Ana

      System.out.println("Saldo da conta de Ana: " + outraConta.getSaldo());

      // Imprima o saldo da conta de Ana, novamente, com outro método

      System.out.println("Saldo da conta de Ana: "

                          + outraConta.getSaldoMonetário());

 

      // Impressao dos objetos

      System.out.println("Situacao da primeira conta: ");

      System.out.println(umaConta);

      System.out.println("Situacao da segunda conta: ");

      System.out.println(outraConta);

   } // fim do método main

} // fim da classe Banco2

  A saída do programa é como segue:

Saldo da conta de Joao: 600.0

Saldo da conta de Ana: 400.0

Saldo da conta de Ana: R$400,00

Situacao da primeira conta:

ContaSimples numero 1, titular Joao, data 26/02/2009, saldo R$600,00

Situacao da segunda conta:

ContaSimples numero 2, titular Ana, data 26/02/2009, saldo R$400,00

·    Este exemplo mostra o conceito de identidade de objetos

·    Os objetos cujas referências são umaConta e outraConta são dois objetos diferentes (com identidade diferente) embora sejam da mesma classe (do mesmo molde)

°      Mesmo que todos os atributos dos dois objetos fossem iguais, eles teriam identidade diferente

i)   Seriam objetos diferentes

ii)          Eles seriam armazenados em lugares diferentes da memória

iii)      A referência é essencialmente o endereço de memória do objeto

·    Observe que, no programa, uma referência a um objeto pode ser passada como parâmetro de um método como qualquer outro valor

·    Identifique isso no programa Banco2

Próximo programa: várias classes

·    Nos programas acima, o titular das contas bancárias não aparece como objeto

·    Suspeitamos de sua existência porque falamos do nome e CPF do titular

·    No próximo programa, trataremos o titular de uma conta de forma explícita como objeto

·    A solução está a seguir:

package p2.exemplos;

 

/*

 * Uso de objetos de várias classes, entrada de dados

 */

 

import p1.aplic.banco.*;

import p1.aplic.geral.*; // para mexer com a classe Pessoa

import p1.io.*; // para fazer entrada de dados

 

public class Banco4 {

   public static void main(String args[]) {

      // declaração de variáveis de 2 classes (tipos) diferentes

      // no fim, teremos 4 objetos de 2 classes

      Pessoa oTitular1, oTitular2;

      ContaSimples umaConta, outraConta;

 

      // tempo de vida: os objetos ainda nao existem

      // a seguinte linha daria erro:

      // umaConta.depositar(1000.0);

 

      // cria dois objetos Pessoa com nome e CPF

      oTitular1 = new Pessoa("Joao", "30914060506");

      oTitular2 = new Pessoa("Ana", "12345678901");

 

      // cria as duas contas

      // Observe que ContaSimples pode ser criada com um titular

      // do tipo Pessoa em vez de dar nome e CPF separadamente

      umaConta = new ContaSimples(oTitular1, 1);

      outraConta = new ContaSimples(oTitular2, 2);

 

      // Vamos ver quanto vamos depositar

      double valorADepositar = Entrada.in

            .lerdouble("Entre com o valor a depositar: ");

      System.out.println("Vou depositar " + valorADepositar);

      umaConta.depositar(valorADepositar);

 

      // Vamos ver quanto vamos transferir

      double valorATransferir = Entrada.in

            .lerdouble("Entre com o valor a transferir: ");

      System.out.println("Vou transferir " + valorATransferir);

      umaConta.transferir(outraConta, valorATransferir);

 

      // Fecha a agencia e guarda toda a informação em arquivo

      Agencia.fecharCaixa();

      System.out.println("OK. Caixa fechado.");

   } // main

} // Banco4

·    Uma possível saída é como segue:

Entre com o valor a depositar: 760

Vou depositar 760.0

Entre com o valor a transferir: 480

Vou transferir 480.0

OK. Caixa fechado.

·    Observe as múltiplas importações

·    Observe a criação de 4 objetos, de 2 classes

°      Quais são as 4 referências?

°      Quais são as 2 classes?

·    A declaração de uma referência não significa que ela "aponte" para um objeto

°      Precisa instanciar o objeto primeiro

·    Observe o construtor de ContaSimples. É diferente das chamadas que vimos até agora

°      nome e cpf não mais passados no construtor da ContaSimples, mas no construtor da Pessoa

°      Neste programa, passamos uma Pessoa como titular e não passamos nome e CPF

°      Isso se chama overload de métodos

i)   Dois métodos com o mesmo nome, mas com parâmetros diferentes são métodos completamente diferentes

°      É semelhante ao overload do operador binário +

·    Observe a chamada ao novo transferir() de ContaSimples

°      Veja o que este método faz aqui

·    Finalmente, tem um método estranho chamado método de classe

Agencia.fecharCaixa();

·    Não há referência a um objeto chamado Agencia

°      Na realidade, Agencia é o nome de uma classe e o método Agencia.fecharAgencia() é um método que pertence à classe em si e não aos objetos da classe Agencia

°      Isso foi feito para simplificar a situação para termos uma única agência

°      Num programa real, a Agencia teria que ser instanciada como qualquer objeto

°      Você pode ver o que o métodos fecharCaixa() faz aqui

°      Como você vai ver, trata-se de salvar os dados das contas, transações, saldos, etc. em arquivo

i)   Chamamos isso de persistência

ii)          Faremos uso disso no próximo programa

Próximo Programa: Acesso a Dados Persistentes

·    Como manipular contas bancárias que já existem?

·    Usaremos um método da classe Agencia para achar uma conta cujo número sabemos

°      Palavra reservada static

°      Você quer ter um campo armazenado em um mesmo espaço de memória, independentemente de quantos objetos da classe existem

(1)               Se vários objetos forem criados eles compartilham os mesmos campos estáticos

°      Você quer um método que não está associado a qualquer objeto específico

(1)               Só acessa campos e/ou métodos de classe

(2)               Os demais precisam estar associados a um objeto específico

 

·    A solução está a seguir

package p2.exemplos;

 

/*

 * Persistência

 */

 

import p1.aplic.banco.Agencia;

import p1.aplic.banco.ContaSimples;

import p1.aplic.banco.Extrato;

import p1.aplic.geral.Data;

import p2.io.Entrada;

 

public class Banco5 {

   public static void main(String args[]) {

      // declaração de variáveis de 3 classes (tipos) diferentes

      // no fim, teremos 4 objetos de 3 classes

      ContaSimples umaConta;

      Extrato umExtrato;

      Data hoje, ontem;

 

      // localiza a conta de número 1

      // (ela já foi criada e armazenada anteriormente)

      // O "cast" (ContaSimples) será explicado em outro momento

      // O motivo é que localizarConta retorna um objeto do tipo Conta

      // que representa uma conta bancária genérica e não apenas uma

      // ContaSimples

      umaConta = (ContaSimples) Agencia.localizarConta(1);

 

      // Vamos fazer um saque

      System.out.println("Voce tem " + umaConta.getSaldoMonetário()

            + " na conta");

 

      double valor =

              Entrada.getValorDoublePositivo("Quanto voce quer sacar? ");

      umaConta.sacar(valor);

 

      // Vamos tirar um extrato de conta entre ontem e hoje

      hoje = new Data(); // hoje representa a data de hoje

      ontem = new Data(); // ontem ainda representa hoje

      ontem.somarDia(-1); // agora, temos a data de ontem

 

      umExtrato = umaConta.criarExtrato(ontem, hoje);

      // Imprime o extrato

      System.out.println(umExtrato.formatar());

      System.out.println("Saldo: " + umaConta.getSaldoMonetário());

 

      // Vamos atualizar as informações persistentes

      Agencia.fecharCaixa();

   } // main

} // Banco5

 

A saída deste programa pode ser como a seguir:

Voce tem R$280,00 na conta

Quanto voce quer sacar? 33

Extrato de conta entre 25/02/2009 15:12 e 26/02/2009 15:12

Data                  Debito Credito           Valor Descricao

26/02/2009 11:13     0000000 0000001        R$760,00 deposito

26/02/2009 11:13     0000001 0000002        R$480,00 transferencia para conta 2

26/02/2009 15:12     0000001 0000000         R$33,00 saque

 

Saldo: R$247,00

·    Observe as várias classes usadas

°      Quais são?

·    Observe como as referências são inicializadas

°      O objeto "umaConta" não é criado com new mas recebido como retorno do método localizarConta() da classe Agencia

°      A classe Agencia achou este objeto num arquivo (salvo no programa Banco4)

·    Observe com que facilidade manipulamos e usamos datas para tirar um extrato

°      Na POO, tudo vira um objeto, até datas, extratos, etc.

·    Estamos fazendo coisas até complexas sem dificuldade

°      Porque abstrações adequadas (classes) já existem para modelar um mundo

Próximo Programa: um Exemplo Usando while e switch

package p2.exemplos;

 

/*

 * Laço: leitura/processamento (até um marcador final)

 */

 

import p1.aplic.banco.ContaSimples;

import p2.io.Entrada;

 

public class Banco8 {

   public static void main(String args[]) {

      final int DEPOSITAR = 1;

      final int SACAR = 2;

      final int SALDO = 3;

      final int SAIR = 4;

      // o caractere de fim de linha pode ser diferente de um sistema para

      // outro exemplo: "\r\n" no MSDOS/Windows, "\n" no UNIX, "\r" no

      // MacIntosh, etc.

      final String fimDeLinha = System.getProperty("line.separator");

 

      final String prompt = "Digite a opcao desejada:" + fimDeLinha

            + DEPOSITAR + ". Depositar" + fimDeLinha + SACAR + ". Sacar"

            + fimDeLinha + SALDO + ". Saldo" + fimDeLinha + SAIR + ". Sair"

            + fimDeLinha + "Opcao: ";

 

      if (args.length != 3) {

         System.err

               .println("Sintaxe: java Banco8 titular cpf numeroDaConta");

         System.exit(1);

      }

 

      ContaSimples aConta = new ContaSimples(args[0], args[1], Integer

            .parseInt(args[2]));

 

      int opção = Entrada.getValorIntPositivo(prompt);

 

      while (opção != SAIR) {

         switch (opção) {

         case DEPOSITAR:

            double valorADepositar = Entrada.getValorDoublePositivo("Entre com o valor a depositar: ");

            aConta.depositar(valorADepositar);

            break;

         case SACAR:

            double valorASacar = Entrada.getValorDoublePositivo("Entre com o valor a sacar: ");

            aConta.sacar(valorASacar);

            break;

         case SALDO:

            System.out.println("Saldo: " + aConta.getSaldoMonetário());

            break;

         default:

            System.err.println("Opcao " + opção + " desconhecida");

            break;

         }

         // leia novamente para voltar ao início do laço

         opção = Entrada.getValorIntPositivo(prompt);

      }

      System.out.println("Saldo final: " + aConta.getSaldoMonetário());

   } // main

} // Banco8

·    A saída do programa:

Digite a opcao desejada:

1. Depositar

2. Sacar

3. Saldo

4. Sair

Opcao: 1

Entre com o valor a depositar: 280

Digite a opcao desejada:

1. Depositar

2. Sacar

3. Saldo

4. Sair

Opcao: 2

Entre com o valor a sacar: 1000

Digite a opcao desejada:

1. Depositar

2. Sacar

3. Saldo

4. Sair

Opcao: 3

Saldo: R$280,00

Digite a opcao desejada:

1. Depositar

2. Sacar

3. Saldo

4. Sair

Opcao: 2

Entre com o valor a sacar: 200

Digite a opcao desejada:

1. Depositar

2. Sacar

3. Saldo

4. Sair

Opcao: 3

Saldo: R$80,00

Digite a opcao desejada:

1. Depositar

2. Sacar

3. Saldo

4. Sair

Opcao: 4

Saldo final: R$80,00

·    Observe a declaração de constantes com a palavra final

°      Nunca usar números mágicos

·    A inicialização de fimDeLinha é um macete para ter portabilidade do programa

°      O programa deve executar corretamente em vários ambientes

°      \r significa "RETURN" e \n significa "NEWLINE"

·    Observe como aConta é criada a partir de argumentos de linha de comando

°      Integer.parseInt(String) converte um String a um inteiro (int)

·    O comando switch implementa uma decisão múltipla

°      Às vezes, pode ser mais legível do que uma seqüência de if-else

O Mundo de Software Simulando o Mundo Real

·    A princípio, o mundo de software será semelhante ao mundo real

·    Classes, objetos e atributos que existem no mundo real normalmente existem no mundo de software que quer tratar do mundo real

·    Portanto, software (aplicações) que lidam com o mundo bancário:

°      Trataria das classes Agência, Conta, Cliente, etc.

°      Teria objetos como no mundo real

°      Esses objetos teriam os mesmos atributos do mundo real

·    O que foi falado acima não é estritamente verdade porque o mundo de software é um modelo do mundo real e só trata das coisas importantes para o business que utilizará o software

°      Exemplo: Clientes têm um tamanho de sapato, mas o software não incluirá este atributo na classe Cliente

·    Apesar de nem sempre ser verdade, é um bom ponto de partida

·    Porém, há diferenças grandes quando pensamos no comportamento

·    Há dois grandes motivos

°      Primeiro motivo: não vamos modelar todo o comportamento dos objetos

i)   Exemplo: Clientes tomam café no mundo real, mas provavelmente não no software

°      Segundo motivo: os comportamentos freqüentemente são assumidos por objetos diferentes

i)   Exemplo: No mundo real, quem faz um depósito? Um Cliente

ii)          No software, qual classe assumiria a responsabilidade de fazer um depósito?

iii)      A classe Conta.

·    Por que isso????

°      A primeira grande regra de programação Orientada a Objeto é a seguinte:

MCj04280650000[1]
 

 

 

 


°      Um depósito afeta duas coisas, do ponto de vista de um sistema bancário:

i)   O saldo de uma conta

ii)          O histórico de transações feitas a uma conta

°      Como se pode ver, o depósito afeta apenas atributos de uma Conta

°      Portanto, a responsabilidade de implementar este comportamento será atribuída à Conta e não ao Cliente, embora, no mundo físico, seja o Cliente que faz o depósito

·    A primeira grande regra acima tem outros nomes:

°      Colocar as responsabilidades com os dados

°      Padrão de Projeto Expert

·    Quem faz algo é quem é o expert nos dados envolvidos

·    Resultado: no mundo de software, objetos são "vivos" não passivos

°      No mundo real, a Conta é passiva, não viva

°      No mundo de software, a Conta faz várias coisas que afetam seus atributos

i)   Saque

ii)          Depósito

iii)      Informar seu saldo, etc.

ProgramaHP da disciplina