1) O documento apresenta fundamentos da programação orientada a objetos em Java, incluindo classes, atributos, métodos, herança, abstração e encapsulamento.
2) A programação orientada a objetos modela sistemas como coleções de objetos que cooperam através de mensagens, ao contrário da programação estruturada que se concentra em funções.
3) Classes descrevem os dados e comportamentos de objetos através de atributos e métodos.
2. Roteiro
• Em poucos slides, apresentar alguns fundamentos importantes
relacionados à Programação Orientada a Objetos
– Características OO em Java: classes, atributos, métodos, herança, abstração,
encapsulamento, polimorfismo, etc...
• Sintaxe Java para construção de entidades complexas
– Componentes de uma classe e sua divisão interna
• Mostrar um exemplo para levantar as vantagens da programação OO
– Exercícios iniciais e exemplos de códigos que você deve testar e solidificar
seus conhecimentos (mas você deve ler um livro!)
2
3. Programação estruturada vs. POO
• Programação estruturada
– Ênfase dada aos procedimentos e funções
– Modela-se a solução de um problema tomando como base as funções a serem
executadas (os verbos!)
verbos
• Programação orientada a objetos
– Modela-se um sistema decidindo-se sobre os objetos
– Estes, então, são caracterizados através de propriedades (que informações
cada objeto deve armazenar?) e comportamento (que tarefas cada objeto
deverá desempenhar?)
3
4. Abstração de casos de uso em
análise OO (I) e análise procedural (II)
4
Referência da figura: [1]
5. Programação estruturada vs. POO
• Algumas considerações importantes:
– desenvolvedor vê seu sistema como uma coleção de objetos cooperantes, que
se comunicam entre si através do envio e recebimento de mensagens
• “Programação orientada a objetos é um método de implementação no
qual programas são organizados como coleções cooperativas de
objetos, cada um representando uma instância de alguma classe, e
objetos classe
estas classes são todas membros de uma hierarquia de classes unidas
via relacionamentos de herança...”[2]
herança
5
6. Como fazer a modelagem inicial?
• Deve-se descobrir quais objetos fazem parte do domínio do problema
• Na POO, cada objeto terá uma estrutura formada por um estado e
um comportamento definidos através de classes
– Definem-se as propriedades (variáveis) e o comportamento (métodos) que
uma categoria de objetos deve possuir
• Uma classe é o modelo ou a fôrma (um template) utilizada para criar
objetos similares (que compartilham as mesmas características).
– Ela também define um novo tipo de dados na linguagem Java.
– Lembre-se: queremos mapear “coisas” do mundo real -> computacional
6
7. Uma boa analogia...
• Uma classe define um novo tipo de dados complexo
• Valores de um tipo definido por uma classe recebem o nome de
objetos
Referência da figura: [4]
7
8. Sintaxe de uma classe
• Estrutura fundamental de programação em Java!
– Todo e qualquer programa Java deve definir pelo menos uma classe.
• Sintaxe básica: Código em Java
(CdPlayer.java)
<modificador> class <nomeDaClasse> {
<modificador> <nomeDaClasse> { class CdPlayer {
int faixaAtual;
faixaAtual;
ATRIBUTO(S) Estado String marca;
marca;
…
…
Comportamento CdPlayer() {…}
CONSTRUTOR(ES)
void tocar() {…}
MÉTODO(S) void parar() {…}
}
}
…
8
9. Atributos
• Definição formal:
– “... o estado de um objeto consiste de todas as propriedades do objeto mais
os valores atuais destas propriedades...”[2]
– cada atributo tem um tipo e armazena um valor que pode variar ao longo
do tempo (é dinâmico!)
/* CdPlayer.java */ Importante:
- a quantidade de propriedades não muda!
class CdPlayer {
CdPlayer {
- os valores guardados são dinâmicos!
int faixaAtual;
String marca; ... criação
double preco; 05
… Objeto
CdPlayer “Gradiente”
};
172.69 9
11. Métodos
• O comportamento de um objeto é dado pelo conjunto de
operações que o mesmo é capaz de realizar
– Entenda isso como sua “interface de uso”
– Um método é um procedimento ou função que permite aos objetos de uma
classe executarem serviços (é a parte da programação imperativa em OO)
• É como o objeto implementa suas funcionalidades
• O envio de uma mensagem para um objeto faz o método
correspondente (de mesmo nome) ser executado
• A mensagem, então, é a ativação de um método sobre o objeto
mensagem
11
12. Classe, estado e comportamento
• Portanto, classes descrevem:
– os dados que compõem os objetos (variáveis)
– procedimentos que o objeto poderá executar (métodos)
Importante: - não é preciso saber os detalhes de implementação!
- o tipo determina a interface de um objeto.
UML - a interface indica que mensagens podem ser enviadas.
Código em Java
Fase de análise Fase de
(...)
(...) Classe Java (tipo)
CdPlayer e projeto implementação
CdPlayer cp;
CdPlayer cp; Referência
faixaAtual:int; variáveis cp = new CdPlayer();
cp = new CdPlayer();
marca:String; instância
preço:double; (sabe) Criação do objeto
tocar():void cp.tocar();
cp.tocar();
parar():void; cp.mudarFaixa(12);
cp.mudarFaixa(12);
mudarFaixa(f:int):void; métodos cp.ejetarCd();
cp.ejetarCd();
repetirCd():void; (faz)
(...)
ejetarCd():void; (...) Envio de mensagem12
13. Boas práticas ao escrever classes
• Use e abuse dos espaços
– Endente com um tab (4 espaços) os membros (métodos, atributos, construtores, etc.) de uma
classe
• A ordem dos membros não é importante, mas melhora a legibilidade do código
– Mantenha os membros do mesmo tipo juntos (não misture métodos com atributos, por exemplo)
– Declare os atributos antes ou depois dos métodos
– Mantenha os construtores juntos, de preferência, bem no início da classe (após os atributos)
– Mantenha os métodos depois dos construtores
13
14. Abstração
• Deve-se abstrair os objetos
– Para entender uma entidade escrita por terceiros, abstraímos a sua
implementação e nos concentramos na sua interface de utilização
• Foca o lado externo de uma entidade ou objeto
• Destaca o comportamento (ou serviços disponíveis) do objeto
• O comportamento essencial do objeto é caracterizado por meio das
operações que ele é capaz de realizar sobre ele mesmo ou sobre outros
objetos
14
16. Abstração
• Conceito de abstração:
– “Processo mental que consiste em escolher ou isolar um aspecto
determinado de um estado de coisas relativamente complexo, a fim de
simplificar a sua avaliação, classificação ou para permitir a comunicação do
avaliação
mesmo [Dicionário Houassis]”
– “Uma abstração denota as características essenciais de um objeto que o
distinguem de outros tipos de objetos e assim provê uma fronteira
conceitual firmemente definida, de acordo com a perspectiva do observador
[Booch]”
16
17. Abstração
• Na programação de computadores:
– Abstrair um conceito é limitar-se a representar este conceito numa
linguagem de programação apenas em seus detalhes necessários à aplicação
• Por exemplo, um sistema bancário abstrai a entidade real Banco em apenas alguns
dados que são importantes (endereço, num. funcionários, nome do banco, etc)
– Não é necessário guardar/conhecer nestes tipos de sistemas como todos
os serviços de um dado banco foram realmente implementados
• Onde são guardadas as contas, como elas foram representadas, etc.
• Estamos interessados em apenas utilizar os serviços de um banco.
17
18. Abstração
• Abstração é um conceito amplo
– Abstração de procedimentos (você já percebeu isto?)
• Dividimos um programa em subprogramas menores e mais fáceis de escrever e
compreender (dividir para conquistar)
• Para usar uma função escrita por terceiros, abstraímos a sua implementação e nos
concentramos na sua interface
– Abstração de dados
• Serve para representarmos entidades reais numa linguagem de computador,
identificando as propriedades destas entidades que realmente interessam no sistema
• Ex.: um cliente poderia ter um nome, idade, salário, etc.
18
19. Abstração
• Em síntese, a ABSTRAÇÃO:
– Uma abstração possui tanto propriedades estáticas quanto dinâmicas
• Atributos que guardam o estado atual da abstração
• As dinâmicas (operações)
• Foca o lado externo de uma entidade ou objeto
– Destaca o comportamento (ou serviços disponíveis) nativo do objeto
• O comportamento essencial do objeto é caracterizado por meio das
operações que ele é capaz de realizar sobre ele mesmo ou sobre outros
objetos
19
20. Encapsulamento
• Foi visto que objetos são formados de duas partes:
Œ interface: métodos declarados (visão externa)
•implementação: a funcionalidade interna (oculta) do objeto
• Geralmente, é interessante proibir acesso aos atributos de dados (e até de
alguns métodos)
– Utilizando-se de modificadores de níveis de acesso extremos, tais como: public
e private (e outros níveis intermediários, fornecidos pela linguagem Java)
– Impacto será menor para quem está usando a classe
• O papel do usuário de classes
– Apenas saber quais os métodos,
parâmetros e o que é retornado
(a interface pública da classe). figura: [2] 20
21. Cenário de utilização
• Visibilidade do encapsulamento em livro:
public class Livro {
public class Livro {
interno
private String titulo;
private String titulo;
private double preco;
private double preco;
public double getPreco(){
public double getPreco(){
return preco;
return preco;
público
}
} Acesso proibido!
public void setPreco(double p){
public void setPreco(double p){
public class
public class Livraria {
Livraria {
preco = (p >=0)? p private int
: preco;
preco = (p >=0)? p private int
: preco; numFuncionarios;
numFuncionarios;
}
} public void
public void cadastrarLivro(String isbn){
cadastrarLivro(String isbn){
...
...
}
}
O acesso irrestrito às public void
public void aplicarDesconto(Livro l){
aplicarDesconto(Livro l){ C
propriedades do Livro
l.preco = -10;
l.preco = -10;
pode levar o mesmo a
um estado ...
...
inconsistente. Veja. }
} 21
* E se amanhã preco mudasse para precoDoLivro?
22. Encapsulamento
• Conceitos complementares:
– A abstração representa um conceito
– O encapsulamento, por sua vez, impede os clientes de verem/conhecerem
como este conceito foi implementado internamente
• Para uma abstração realmente funcionar, sua implementação deve
estar encapsulada
• Os objetos são formados de duas partes:
– Uma interface (visão externa)
– Uma implementação (a funcionalidade interna e oculta)
22
23. Encapsulamento (cont.)
• A implementação não interessa à quem usa os objetos
• Papel do usuário de classes
– Não precisa saber como a classe foi escrita, apenas quais seus métodos, quais os
parâmetros (quantidade, ordem e tipo) e os valores que são retornados
– Usa apenas a interface pública da classe
• Papel do desenvolvedor de classes
– Define novos tipos de dados
– Expõe, através dos métodos, todas as funções necessárias aos usuários das classes e
oculta o resto da implementação
– Tem a liberdade de mudar a implementação das classes que cria sem que isto
comprometa as aplicações desenvolvidas pelos usuários das classes
23
24. Métodos de acesso
• Uma vez que o encapsulamento favorece a evolução do sistema,
geralmente, faz-se necessário definir métodos de acesso em atributos:
– acessar/ler get<XXX>( ) ou alterar set<XXX>() os valores das
propriedades de objetos
public class Livro {
public class Livro {
Implementação foi
interno
private String titulo;
private String titulo;
encapsulada com o private double preco;
private double preco;
uso de private public double getPreco(){
public double getPreco(){
return preco;
return preco;
}
público
}
Método que retorna public void setPreco(double p){
public void setPreco(double p){
Previne valores
um valor (double) preco = (p >=0)? p : preco;
preco = (p >=0)? p : preco;
inconsistentes
}
} 24
* Há casos de métodos private e atributos públicos
25. Criação de objetos
• Para criar objetos, algumas linguagens implementam certos “métodos
especiais”, ou construtores
– Utilizados para criar e/ou inicializar novos objetos
• Em Java, os construtores têm o mesmo nome da classe
• A alocação de todo o objeto em memória é feita com o uso do
operador new
– Aloca o objeto na memória do tipo de uma classe e devolve o endereço para
ser usado numa variável Livro l = new Livro();
C
Livro l = new Livro();
l.setPreco(126.80);
l.setPreco(126.80);
Lembre-se: objetos precisam ser
double valor = l.getPreco();
double valor = l.getPreco();
criados antes de serem usados 25
26. Construtores
• Lembre-se: para a criação de objetos, Java garante que cada
classe tenha ao menos um construtor
– O construtor default recebe zero argumentos
– Faz apenas a inicialização da superclasse
• Construtor default (sem argumentos) só existe (é fornecido) quando
não há nenhum outro construtor definido explicitamente no código
– A criação de um construtor explícito substitui o construtor fornecido
implicitamente pelo sistema
– Mas a inicialização da superclasse continua garantida
26
27. Graficamente
public class Livro {
public class Livro {
C
interno
private String titulo;
private String titulo;
private double preco;
private double preco; Dica: Construtor já estaria “em
public Livro(){ dia”com as regras de validação
public Livro(){
definidas em métodos de acesso.
super();
super();
público
}
} public class Livro {
public class Livro {
private String titulo;
interno
public double getPreco(){…} private String titulo;
public double getPreco(){…}private double preco;
private double preco;
public void setPreco(double p){…}
public void setPreco(double p){…}
// construtor explícito
// construtor explícito
public Livro(String t, double p){
public Livro(String t, double p){
titulo = t; // setTitulo(t);
titulo = t; // setTitulo(t);
Construtor default faz preco = p; // setPreco(p);
preco = p; // setPreco(p);
}
}
apenas a inicialização
public double getPreco(){…}
public double getPreco(){…}
da superclasse
público
public void setPreco(double p){…}
public void setPreco(double p){…}
(construtor de Object) public String getTitulo(){…}
public String getTitulo(){…}
public void setTitulo(String t){…}
public void setTitulo(String t){…}
Poderia ter outros }
}
construtores* 27
* Distinção é feita pelo número e tipo de argumentos (ou seja, pela assinatura do construtor)
28. Ciclo de vida de um Objeto
• A linha da vida de um objeto:
1) Instanciação: o objeto é criado e passa a ser referenciado por um
nome (sua referência);
2) Uso: o objeto recebe mensagens de outros objetos e, com isso, executa
parte da funcionalidade do sistema;
3) Destruição: a área de memória ocupada pelo objeto é
reclamada...todas as referências para o objetos ficam nulas.
• A destruição de um objeto é realizada automaticamente pelo coletor de lixo!
• Minimiza o trabalho do programador.
28
29. Exemplo – Ciclo de vida de um Objeto
Quadrado q;
q = new Quadrado();
q.moverDireita(20);
q.mudarTamanho(5);
q.ficarVisivel(false);
q.mudarCor(“red”);
q = null;
29
30. Exemplo – Ciclo de vida de um Objeto
• Esquematicamente:
q
new
tamanho: 5
cor: “red”
visivel: false
Referência da figura: [4]
30
31. Instanciação de Objetos
• Definição
– Operação através da qual um objeto é criado e passa a existir na memória
do computador. A classe é o modelo ou a fôrma utilizada para criar o objeto.
• Objeto versus referências
– Os objetos são manipulados através de referências ou ponteiros que indicam
onde o objeto está localizado na memória do computador
– Não há outra forma de chegar ao objeto sem que seja via uma referência.
• Lembre de Bruce Eckel e sua analogia do controle da televisão!
31
32. Referências para objetos
• A maioria dos objetos em um programa Java são acessados por
variáveis chamadas de referências
• Como Java é uma linguagem fortemente tipada, estas variáveis
tipada
devem ser declaradas e tipificadas em tempo de compilação
• Exemplos:
String s; // s é do tipo String
Quadrado q1; // q1 é do tipo Quadrado
Cliente c; // c é um cliente
32
33. Referências para objetos
• Referências são ponteiros para o objeto
Quadrado q; // declaração
q = new Quadrado(); // instanciação
q.mudeTamanho(50); // uso
q = null; // desprezo
q
33
34. Referências para objetos
• Referências são ponteiros para o objeto
Quadrado q; // declaração
q = new Quadrado(); // instanciação
q.mudeTamanho(50); // uso
q = null; // desprezo
q
tamanho: 30
34
35. Referências para objetos
• Referências são ponteiros para o objeto
Quadrado q; // declaração
q = new Quadrado(); // instanciação
q.mudeTamanho(50); // uso
q = null; // desprezo
q
tamanho: 50
35
36. Referências para objetos
• Referências são ponteiros para o objeto
Quadrado q; // declaração
q = new Quadrado(); // instanciação
q.mudeTamanho(50); // uso
q = null; // desprezo
Objeto sem
q referência!
tamanho: 50
36
37. Variáveis de classe
• Foi visto que as variáveis de instância residem dentro de objetos e possuem
valores (geralmente) individuais
– Cada vez que um objeto é criado, novas propriedades são alocadas para uso daquele
objeto em particular
• Às vezes, um sistema pode ter variáveis contendo informações úteis, como:
– Número de objetos instanciados pela classe até certo instante
– Valor médio, mínimo.. public class Agencia
public class Agencia {
{
interno
private
private String endereco;
String endereco;
• Pense um pouco: private
private int numFuncionarios;
int numFuncionarios;
private
private double juros;
double juros;
sdfdsfsdfsdfsdfdsfdsfdsfdsfdsfdsdsfdssdfsdfada um dos objetos?
Imagine um sistema bancário onde o juros é
compartilhado pelas agências de uma rede public String getEndereco(){…}
público
public String getEndereco(){…}
de bancos.
public void ligarAlarme(){…}
public void ligarAlarme(){…}
Seria interessante armazenar este dado em
cada instância? }
} 37
38. Graficamente
1ª tentativa 2ª tentativa
Tornar esta variável como A única cópia residindo apenas na classe
propriedades das instâncias (alterações apenas em um local)
Sistema Sistema
Operacional Operacional
Classes Classes
a1 objAgManaíra a1 objAgManaíra
a2 a2
objAgTambaú objAgTambaú
Heap
a3 a3
objAgVaradouro objAgVaradouro
0xFF29 0xFF29
0x3294 0x3294
0x5549 0x5549
Pilha Pilha 38
39. Resumo
• Os objetos instanciados pela classe podem acessar as variáveis de
classe (para modificar ou ler o valor)
• A modificação numa variável de classe é percebida por todos os
objetos
• A variável de classe fica armazenada na classe e não nas instâncias
geradas public class Agencia {
public class Agencia {
interno
• É comum o uso em destas
para definir constantes
private String endereco;
private String endereco;
C
private int numFuncionarios;
private int numFuncionarios;
public static final double juros;
public static final double juros;
public String getEndereco(){…}
– PI, MAX_IDADE,... public String getEndereco(){…}
público
public void ligarAlarme(){…}
public void ligarAlarme(){…}
}
} 39
40. Strings
• Você deve ter percebido no curso de Java básico que não existe o tipo
primitivo String em Java
– Em verdade, string’s em Java são objetos!
– A API Java possui uma classe chamada String
– Esta, apresenta um rico conjunto de métodos utilitários que permitem
extrair o tamanho, buscar caracteres, sub-strings, comparações…
public class UsaString {
public class UsaString {
public static void main(String[] args){
public static void main(String[] args){
String s1 = “Maria”;
String s1 = “Maria”;
String s2 = new String(“Maria”);
String s2 = new String(“Maria”);
if( s1 == s2 ) //falso
if( s1 == s2 ) //falso
if( s1.equals(s2) ) // verdadeiro
if( s1.equals(s2) ) // verdadeiro
System.out.print( s1 + “ da Silva” );
System.out.print( s1 + “ da Silva” );
}
} 40
41. Arrays
• Arrays em Java também são objetos e armazenam elementos de um
determinado tipo em particular
• Porém, como temos duas categorias de tipos em Java, é possível
declarar arrays:
Œ Primitivos: armazenam tipos primitivos nas células
• Referência: armazenam referências (nunca objetos inteiros) em cada
inteiros
célula
public class ArrayPrimitivo {
public class ArrayPrimitivo { public class ArrayReferencia {
public class ArrayReferencia {
public static void main(…){
public static void main(…){ public static void main(…){
public static void main(…){
int[] vi = {55,66,77};
int[] vi = {55,66,77}; Livro[] vl = new Livro[3];
Livro[] vl = new Livro[3];
double[] vd = new double[7];
double[] vd = new double[7];
vl[0] = new Livro();
vl[0] = new Livro();
vd[6] = 99.5;
vd[6] = 99.5; vl[0].setTitulo(“O Sol”);
vl[0].setTitulo(“O Sol”);
vi[2] = 88;
vi[2] = 88;
}
} }
} 41
42. Herança
• Permite reutilizar as características de uma classe (base) na definição de uma
outra classe derivada e mais específica
– Reutilização direta de código previamente definido por alguém em uma superclasse
• Terminologias relacionadas à Herança
– Classes mais generalizadas: superclasses
– Mais especializadas: subclasses
– Na herança, classes estão ligadas à uma hierarquia
– É a contribuição original do paradigma OO
• Linguagens como Java, C++, Object Pascal, …
42
43. Árvore de herança
• Imagine a modelagem de um sistema para um jogo de luta infantil
para computador (com personagens)
Personagem public class Personagem {
saltar();
Classe que define falar(); public void saltar(){
uma interface arma(); System.out.println(“Pular”);
comum a todos os }
personagens
public void falar(){
System.out.println(“Avançar!”);
Soldado General }
public void arma(){
arma(); arma();
System.out.println(“Desarmado”);
}
}
public class Soldado
public class Soldado Subclasses redefinem comportamentos específicos
extends Personagem{
extends Personagem{ public class General
public class General
public void arma(){
public void arma(){ extends Personagem {
extends Personagem {
System.out.println(“Tiro”); public void arma(){
System.out.println(“Tiro”); public void arma(){
}
} System.out.println(“Rajada”);
System.out.println(“Rajada”);
Implementações de falar e saltar serão
}
} usadas da superclasse } Implementações de falar e saltar
} 43
} serão usadas da superclasse
}
44. Árvore de herança
• União das classes que herdam entre si gera uma árvore de herança
(ou uma hierarquia de classes relacionadas)
– Todos os objetos herdam características (gerais) definidas em Personagem
– Soldado e General são especializações de Personagem (são tipos de
Personagem)
• Em todos os casos, cada subclasse possui uma única superclasse
– A isso, chamamos de herança simples
• Em algumas linguagens, é possível herdar a partir de diversas
superclasses (e.g., C++)
44
45. Benefícios da herança
• Quando relacionamos duas classes via herança, podemos ter
polimorfismo com ligação dinâmica
– Se um fragmento de código usa uma referência de uma superclasse
(Personagem), esta pode manipular novos tipos concretos futuros
• Por exemplo: um novo tipo de personagem (Tenente)
– Isso porque a ligação dinâmica irá garantir que os métodos certos (saltar(),
arma(), ...) sejam chamados corretamente
Jogo.java
Novo tipo ...
...
void jogar(Personagem p){
void jogar(Personagem p){
p.arma();
p.arma();
Tenente
}
}
...
...
j1.jogar(new Tenente());
j1.jogar(new Tenente());
45
46. Polimorfismo
• Polimorfismo (poli=muitos, morfo=forma) é uma
característica essencial de linguagens OO
• Como funciona?
– Uma referência que faz papel de interface serve de intermediária fixa entre o
programa-cliente e os objetos que, na verdade, irão executar as mensagens
daquele tipo em particular
– O programa-cliente não precisa (e não quer) saber da existência dos outros
(ou futuros) objetos
– Objetos podem ser substituídos sem que os programas-cliente (que usam os
métodos desta interface) sejam afetados negativamente
46
47. Interface vs. implementação
Estabelece uma
interface comum
• Polimorfismo permite separar a interface da
implementação
• A classe base define a interface comum
– Não precisa dizer como isto vai ser feito
Não diz: um General ou um Soldado pode saltar ou falar
ou ter uma arma
– Diz apenas que os métodos existem, que eles
retornam determinados tipos de dados e que
requerem certos parâmetros ...
...
Implementações da interface
void jogar(Personagem p){
void jogar(Personagem p){
Diz: um Personagem pode saltar, falar, e ter uma arma p.saltar(); fazer)
(dizem como
p.saltar();
p.falar();
p.falar();
p.arma();
p.arma();
}
}
47
48. Importante!
• No exemplo anterior, utilizamos o extends (estamos utilizando a herança de
classes)
– Ao fazer herança, subclasses de Personagem (Soldado, etc.) vão herdar todos os
métodos (não-private) da superclasse
– Isto significa que, com herança, vou herdar o tipo da superclasse e também sua
implementação (herança de implementação)
– Ao herdar, a subclasse pode fazer override (substituir) de alguns métodos (foi isso
que Soldado fez: ele decidiu poder usar a arma de forma diferente de General, por
exemplo)
– Isso significa que objetos da classe Soldado ou da classe General terão formas
diferentes de implementar o método arma()
– Portanto, haverá polimorfismo ao chamar p.arma()
48
49. Ligação dinâmica
• No exemplo anterior, temos um programa com objetos das classes Soldado e
General (e outros)
– Portanto, temos duas implementações diferentes do método arma() em cada uma
das (sub)classes.
– Quando chamamos p.arma(), através da interface, um desses três métodos será
chamado (isso vai depender do objeto que receberá a mensagem)
– Achar qual método certo a ser chamado para um objeto em particular chama-se dynamic
binding (ou amarração dinâmica)
– Ora, temos que amarrar a chamada p.arma() a uma das implementações de
arma()em tempo de execução
49
50. Exemplo
• Executando os códigos:
public class Personagem {
interno
public class saltar(){
public void Tenente
public class Tenente
System.out.println(“Pular”);
extends Personagem{
extends Personagem{
};
public class arma(){
public void Soldado
public class arma(){
public void Soldado
System.out.println(“Tiro”);
System.out.println(“Tiro”);
public void falar(){ Personagem {
extends Personagem {
extends
}public void arma(){
}public classarma(){
System.out.println(“Avançar!”);
public void General
public class General
} System.out.println(“Rajada”); {
}
} extends Personagem
System.out.println(“Rajada”); {
extends Personagem
public void arma(){ public class UsaPersonagem {
public class UsaPersonagem {
}public void arma(){ public static void main(String[] args){
public void arma(){ public static
}System.out.println(“Desarmado”); void main(String[] args){
}}
} System.out.println(“Rajada”); p;
Personagem
System.out.println(“Rajada”); p;
Personagem
} } } p = new Soldado();
p = new Soldado();
}
} p.arma(); // imprime “Tiro”
p.arma(); // imprime “Tiro”
p = new General();
p = new General();
Note a presença do p.arma(); // imprime “Rajada”
p.arma(); // imprime “Rajada” C
supertipo p = new Tenente();
p = new Tenente();
p.arma(); // imprime “Desarmado”
p.arma(); // imprime “Desarmado”
}
}
Ligação dinâmica
50
51. Considerações finais
• Usa objetos, e não procedimentos como bloco lógico fundamental
para a construção de programas
• Cada objeto é uma instância de uma classe
• Objetos possuem estado e comportamento e comunicam-se
através de mensagens
• Classes são relacionadas com as outras via mecanismos de herança,
formando uma hierarquia de classes
• Polimorfismo e ligação tardia
51
53. O que você deve ter em mente?
• Características da Prog. Imperativa
– Ênfase muito grande dada aos procedimentos e funções
• Modela-se a solução de um problema tomando-se como base as funções a serem
executadas (retira-se os verbos!)
verbos
– Dados são tratados de forma secundária
• Variáveis globais são criadas com o objetivo de atender a todos os módulos
• Estes dados estão acessíveis e podem ser corrompidos
– Paradoxo
• Dados são importantes!
• Sem os dados ,os procedimentos não teriam utilidade prática
53
54. Programação Orientada a Objetos
• Características da Prog. Orientada a Objetos
– A ênfase aqui é dada às estruturas de dados, adicionando-se funcionalidades
a elas (serviços que irão operar sobre esta camada de dados)
– Modela-se um sistema decidindo os objetos necessários
• Estes, então, são caracterizados através de propriedades (que informações cada
objeto deve armazenar?) e comportamento (que tarefas cada objeto deverá
desempenhar?)
• A ênfase, aqui, é dada aos substantivos (bons indicadores na geração dos futuros
objetos que irão compor o sistema)
sistema
• Modela-se estas entidades utilizando-se, geralmente, da linguagem UML
54
55. Exemplo de uma aplicação:
OO versus Procedural
• Estudo de caso breve e simples
– Implementando um sistema de caixa numa linguagem procedural e
numa orientada a objetos
• O que é um sistema de caixa?
– É um sistema que cadastra produtos e clientes e relaciona-os numa venda
– Operações básicas deste tipo de sistema (resumidamente...)
• Incluir produto numa venda, cadastrar um novo cliente, calcular total de uma
venda, fechar venda, etc.
55
56. Exemplo de uma aplicação:
OO versus Procedural
• Primeira pergunta:
– Que estrutura básica da linguagem será utilizada para armazenar os dados?
• Resposta: depende das estruturas construtoras de tipo existentes na linguagem
• Como modelar isso utilizando a linguagem C?
• Segunda questão:
– Como fazer para que o acesso a estas estruturas de informações seja feito e
que possamos materializar as operações descritas anteriormente?
• Resposta: utilizando subprogramas
56
57. Exemplo de uma aplicação:
OO versus Procedural
• O sistema em C:
Nome do novo tipo que define a
estrutura de uma venda
struct tvenda {
struct tvenda {
int cliente;
int cliente; Indica quem é o cliente da venda
char data[8];
char data[8]; A data da venda
int itens[MAX_ITENS];
int itens[MAX_ITENS]; Os itens da venda
} vendas[MAX_VENDAS];
} vendas[MAX_VENDAS];
Variável que guarda as vendas
57
58. Exemplo de uma aplicação:
OO versus Procedural
• Outras estruturas do sistema:
struct tcliente {
struct tcliente {
char nome[50]; Estrutura para clientes
char nome[50];
char endereco[50];
char endereco[50];
} clientes[MAX_CLI];
} clientes[MAX_CLI];
struct tproduto {
struct tproduto {
int codigo;
int codigo;
char descricao[50];
char descricao[50]; Estrutura para produtos
float preco;
float preco;
} produtos[MAX_PROD];
} produtos[MAX_PROD];
58
59. Exemplo de uma aplicação:
OO versus Procedural
• Operações do sistema (um arquivo de funções):
float total_venda(struct tvenda *v, int cliente);
float total_venda(struct tvenda *v, int cliente);
int abrir_venda(struct tvenda *v, int cli, char *data);
int abrir_venda(struct tvenda *v, int cli, char *data);
float fecha_venda(struct tvenda *v, int cliente);
float fecha_venda(struct tvenda *v, int cliente);
int procura_produto(struct tproduto *p, char *nome);
int procura_produto(struct tproduto *p, char *nome);
void insere_cliente(struct tcliente *c, struct tcliente
void insere_cliente(struct tcliente *c, struct tcliente
ncliente);
ncliente);
float valor_produto(struct tproduto *p, int codprod);
float valor_produto(struct tproduto *p, int codprod);
int adicione_item(struct tvenda *v, int codprod);
int adicione_item(struct tvenda *v, int codprod); 59
60. Exemplo de uma aplicação:
OO versus Procedural
• Após a finalização das estruturas e funções:
60
61. Exemplo de uma aplicação:
OO versus Procedural
• Usando as funções numa aplicação:
Void realiza_venda( int cliente ){
Void realiza_venda( int cliente ){
vendas[i] = cliente;
vendas[i] = cliente;
vendas[i].data = hoje();
vendas[i].data = hoje();
while (true) { Acesso direto as estruturas do tipo
while (true) {
p = leia_produtoGUI();
p = leia_produtoGUI();
if (p == FIM) break;
if (p == FIM) break;
vendas[i].itens[j] = p;
vendas[i].itens[j] = p;
}} E se a implementação mudasse
para uma lista encadeada?
}} 61
62. Exemplo de uma aplicação:
OO versus Procedural
• Problemas com a estratégia mostrada
– Relacionamento tênue entre os dados
– Fraco acoplamento entre os dados e as funções que os manipulam
• Um dado incorreto neste sistema pode influenciar QUALQUER função que o manipule
• Todas as funções são pares entre si (não há uma hierarquia ou qualquer
agrupamento lógico entre elas... apenas físico
– Não há encapsulamento das abstrações (tipos) que foram definidas
pelo usuário
– Uma estrutura conhece muito sobre a outra...
62
63. Exemplo de uma aplicação:
OO versus Procedural
• O sistema em Java
public class Venda{
public class Venda{
Novo tipo
private Cliente cliente;
private Cliente cliente;
private Date data;
private Date data; Dados
private ArrayList itens;
private ArrayList itens;
public Venda( Cliente c, Date d );
public Venda( Cliente c, Date d );
float total();
float total(); As operações
int addItem( Produto p );
int addItem( Produto p );
}}
63
64. Exemplo de uma aplicação:
OO versus Procedural
• O sistema em Java
public class Cliente {
public class Cliente {
private String nome;
private String nome;
private String endereco;
private String endereco;
public Cliente( String n, String e );
public Cliente( String n, String e );
void mudaNome( String novoNome );
void mudaNome( String novoNome );
void mudaEndereco( String novoEnd );
void mudaEndereco( String novoEnd );
}}
64
65. Exemplo de uma aplicação:
OO versus Procedural
• O sistema em Java
public class Produto {
public class Produto {
private String nome;
private String nome;
private String descricao;
private String descricao;
private float preco;
private float preco;
public Produto( String n, String d, float p );
public Produto( String n, String d, float p );
void mudaPreco( float novoPreco );
void mudaPreco( float novoPreco );
String pegueDescricao();
String pegueDescricao();
}}
65
66. Exemplo de uma aplicação:
OO versus Procedural
• Após a finalização das estruturas e funções:
66
67. Exemplo de uma aplicação:
OO versus Procedural
• O sistema em Java
public class Loja {
public class Loja {
... // código da classe loja...
... // código da classe loja...
Venda realizaVenda( Cliente c ){
Venda realizaVenda( Cliente c ){
Venda v = new Venda( c, hoje() );
Venda v = new Venda( c, hoje() );
Produto p;
Produto p;
while (true) {
while (true) {
p = GUI.leiaProduto();
p = GUI.leiaProduto();
v.addItem( p );
v.addItem( p );
} Não há possibilidade de acessar o
}
interior dos objetos Cliente, Venda e
return v;
return v; Produto a partir deste código !
}}
}}
67
68. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema imperativo
– Diferenciar vendas a prazo de vendas feitas à vista
struct tvendavista {
struct tvendavista {
int cliente;
int cliente;
char data[8];
char data[8];
int itens[MAX_ITENS];
int itens[MAX_ITENS];
float desconto;
float desconto;
} vendas_vista[MAX_VENDAS_VISTA];
} vendas_vista[MAX_VENDAS_VISTA];
68
69. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema imperativo
– Diferenciar vendas a prazo de vendas feitas à vista
struct tvendaprazo {
struct tvendaprazo {
int cliente;
int cliente;
char data[8];
char data[8];
int itens[MAX_ITENS];
int itens[MAX_ITENS];
int parcelas;
int parcelas;
float juros;
float juros;
} vendas_prazo[MAX_VENDAS_PRAZO];
} vendas_prazo[MAX_VENDAS_PRAZO];
69
70. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema imperativo
– Agora... mudanças nas funções
float total_vendasV(struct tvendavista *va,
float total_vendasV(struct tvendavista *va,
int i);
int i);
float total_vendasP(struct tvendaprazo *vp,
float total_vendasP(struct tvendaprazo *vp,
int i);
int i);
int add_itemv(struct tvendavista *va, int cli,
int add_itemv(struct tvendavista *va, int cli,
char *data)
char *data)
int add_itemv(struct tvendavista *va, int cli,
int add_itemv(struct tvendavista *va, int cli,
char *data)
char *data) Código difícil de manter!
Duplicação desnecessária! 70
71. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema imperativo
– Acabou? Ainda não! Isso implica uma função print para cada tipo de venda
void print_vendaV(struct tvendavista *va);
void print_vendaV(struct tvendavista *va);
float print_vendaP(struct tvendaprazo *vp);
float print_vendaP(struct tvendaprazo *vp);
71
72. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema em Java
public class Venda {
public class Venda {
private Cliente cliente;
private Cliente cliente;
private Date data;
private Date data;
private ArrayList itens;
private ArrayList itens;
public Venda( Cliente c, Date d );
public Venda( Cliente c, Date d );
float total();
float total();
int addItem( Produto p );
int addItem( Produto p );
}}
public class VendaVista extends Venda {
public class VendaVista extends Venda {
...
...
private float desconto;
private float desconto;
}}
72
73. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema em Java
public class Venda {
public class Venda {
private Cliente cliente;
private Cliente cliente;
private Date data;
private Date data;
private ArrayList itens;
private ArrayList itens;
public Venda( Cliente c, Date d );
public Venda( Cliente c, Date d );
float total();
float total();
int addItem( Produto p );
int addItem( Produto p );
}}
public class VendaPrazo extends Venda {
public class VendaPrazo extends Venda {
...
...
private int parcelas;
private int parcelas;
private float juros;
private float juros;
}}
73
74. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema em Java
public class Venda {
public class Venda {
private Cliente cliente;
private Cliente cliente;
private Date data;
private Date data;
private ArrayList itens;
private ArrayList itens;
public Venda( Cliente c, Date d );
public Venda( Cliente c, Date d );
float total(); Função comum aos
float total();
int addItem( Produto p ) {...} ;
int addItem( Produto p ) {...} ; dois tipos de venda!
}}
public class VendaVista extends Venda {
public class VendaVista extends Venda {
...
... Função específica!
public float total() {...};
public float total() {...};
}}
74
75. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema em Java
public class Venda {
public class Venda {
private Cliente cliente;
private Cliente cliente;
private Date data;
private Date data;
private ArrayList itens;
private ArrayList itens;
public Venda( Cliente c, Date d );
public Venda( Cliente c, Date d );
float total();
float total();
int addItem( Produto p ) {...} ;
int addItem( Produto p ) {...} ;
}}
public class VendaPrazo extends Venda {
public class VendaPrazo extends Venda {
...
... Função específica!
public float total() {...};
public float total() {...};
}}
75
76. Exemplo de uma aplicação:
OO versus Procedural
• Reutilização no sistema em Java
– Polimorfismo!
public class Loja {
public class Loja {
...
...
public void printVenda( Venda v ) {...} ;
public void printVenda( Venda v ) {...} ;
}}
Esta função aceita os dois tipos de
venda! Podemos passar como
parâmetro tanto um objeto
VendaVista como VendaPrazo.
76
77. Exemplo de uma aplicação:
OO versus Procedural
• Conclusões
– Na OO, os dados não estão disponíveis globalmente, mas modularizados e
confinados (encapsulados) sob a parte do sistema (funções) que sabe tratá-
los e tem alguma relação com eles (coesão)
– Entretanto, na programação imperativa, todas as funções estão no mesmo
nível hierárquico e podem, potencialmente, acessar qualquer dado da
aplicação
• A manutenção tanto corretiva quanto expansiva são muito difíceis de serem
realizadas
77
78. Exemplo de uma aplicação:
OO versus Procedural
• Conclusões
– Uma classe em Java permite que vários objetos daquela classe possam ser
criados e passem a existir independentemente uns dos outros
– O polimorfismo e a herança permitem que o processamento comum a tipos
equivalentes seja realizado de uma vez só
• Isso evita a criação de diversas funções com assinaturas diferentes, mas que,
semanticamente, são muito semelhantes.
78
79. Para um melhor aproveitamento…
• Ao codificar exemplos mostrados em sala, procure verificar pontos de
dúvidas com o professor.
• Não estude apenas por slides (são apenas tópicos)!
• Mantenha em dia todas as questões das listas de exercícios e práticas
de laboratório.
• Não se acanhe! Procure-me (ou monitor da disciplina, quando houver
algum) e questione conceitos, listas, etc.
• Não deixe para começar a estudar em cima da hora.
79
80. Créditos para geração desta nota de aula
• [1] ROCHA, Helder da. Desenvolvimento de Aplicações com Java. Disponível em:
<http://www.argonavis.com.br/cursos/java/j100/index.html>
• [2] Booch, G.; Maksimchuk, R. A.; Engel, M. W.; Young, B.J. Object-Oriented-Analysis-
Design-Applications. 3rd.Ed. Addison Wesley, 2007
• [3] The Java Tutorial. Disponível em: http://java.sun.com/docs/books/tutorial/
• [4] PEREIRA, Frederico C. G.; Slides do Curso de Java. Disponível por WWW em
http://asterix.coinfo.cefetpb.edu.br/~fred
80
81. Bibliografia Complementar
• Bibliografia principal:
– (1) SIERRA, K.; BATES, B. Use a Cabeça JAVA. Editora Alta Books, 2ª ed. Rio de Janeiro 2007.
– (1)DEITEL, H. M. ; DEITEL, P. Java - Como programar. 6ª Edição, Prentice-Hall, 2005.
– FLANAGAN, D., Java in a Nutshell : A Desktop Quick Reference, O'Reilly & Associates,
1999 (bom para consultar a documentação)
• Bibliografia disponível para download (grátis):
– CAMPIONE, M. e WALRATH, K. The Java Tutorial: Object-Oriented Programming for
the Internet. Addison-Wesley (http://java.sun.com/docs/books/)
– (2) ECKEL, B., Thinking in Java. Prentice Hall. (http://www.mindview.net/Books/TIJ/)
81