Escolar Documentos
Profissional Documentos
Cultura Documentos
Introdução à
gestão de
versões
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ A Gestão de Versão
▸ Utilização de Git
2
Problema
3
Problema
▸ Imagine que escreveu um programa que estava
a funcionar mas que depois o estragou ao
implementar uma nova funcionalidade.
▹ Como iria conseguir recuperar a versão
funcional?
▹ É mesmo possível?
▹ Como fez no projeto da disciplina de IPOO?
4
Solução
▸ Recuperar a versão funcional do seu código só
é possível se tiver criado uma cópia da versão
antiga do código.
▸ O perigo de perder as versões funcionais
geralmente leva ao fluxo de trabalho
problemático ilustrado no cartoon PhD Comics
mostrado anteriormente.
5
“ ▸ O controlo de versão é
usado para rastrear e
armazenar alterações
num conjunto de
ficheiros sem perder o
histórico de alterações
anteriores.
6
Sistema de controlo de versão
7
O que é controlo de versão?
8
Aspectos chave
▸ O controlo de versão permite:
▹ Voltar facilmente à uma versão anterior
▹ O controlo de versão é como um "undo" ilimitado.
▹ Seguir a evolução do projeto ao longo do tempo
▹ O trabalho em paralelo em partes disjuntas do projeto e gerir as modificações
concorrentes
▹ Facilitar a deteção de erros
▹ ….
9
Histórico
▸ Anos 1980: sistemas automatizados de controle
▹ RCS, CVS ou Subversion
▹ usados por muitas empresas grandes.
▹ Sistemas desatualizados devido a várias limitações nas suas
funcionalidade.
▸ Sistemas mais modernos: como Git e Mercurial,
▹ Distribuídos: não precisam de um servidor centralizado para
alojar o repositório.
▹ Ferramentas de fusão poderosas (merging) : vários autores
trabalhem nos mesmos ficheiros simultaneamente.
10
Sistema local
Vantagens
Gestão e utilização muito
simples
Desvantagens
Muito sensível às avarias
Não permite a colaboração
11
Sistema centralizado
Vantagens
▸ Estrutura simples
▸ Gestão e utilização muito
simples
Desvantagens
▸ Muito sensível às avarias
▸ Não adaptado aos grandes
projetos e / ou à uma estrutura
muito hierarquizada a
colaboração
12
Sistema distribuído
Vantagens
▸ Menos sensível às avarias
▸ Adaptado aos grandes projetos e / ou
à uma estrutura muito hierarquizada
Desvantagens
▸ Gestão e utilização mais
complicadas
▸ Pode ter uma estrutura muito
complexa
13
git - sistema de gestão de versão distribuído
▸ Histórico (Wikipedia)
▹ De 1991 a 2002, o núcleo de Linux estava a ser desenvolvido
sem usar sistema de gestão de versão.
▹ A partir de 2002, a comunidade começou a usar BitKeeper,
um DVCS proprietário.
▹ Em 2005, depois de um contencioso, BitKeeper retira a
possibilidade de usar gratuitamente o seu produto. Linus
Torvalds lança o desenvolvimento de Git e após alguns
meses de desenvolvimento, Git aloja o desenvolvimento do
núcleo Linux
14
Git – princípios de base
▸ Um repositório Git é uma espécie de sistema de ficheiros (base de dados),
que guarda as versões dos ficheiros de um projeto em determinados
momentos, ao longo do tempo sob a forma de instantâneos (snapshots).
15
Git – princípios de base
3 zonas num projeto Git
▹ O repositório Git: contém os
metadados e a base de dados dos
objetos do projeto
▹ O diretório de trabalho: extração
única da versão do projeto desde a
base de dados do repositório
▹ A zona de trânsito / índex: simples
ficheiro que contém as informações
sobre o que será considerado na
próxima submissão/commit.
16
Git – princípios de base
4 estados de um ficheiro no Git
▹ não “versionado”: ficheiro não gerido ou
que deixou de ser gerido pelo Git;
▹ não modificado: ficheiro guardado de
forma segura na sua versão atual na base
de dados do repositório;
▹ modificado: ficheiro que sofreu
modificações desde a última vez que houve
um commit;
▹ Indexado (staged): idêntico ao modificado,
só que será integrado no próximo
instantâneo na sua versão corrente durante
o próximo commit
17
Git – princípios de base
Cada submissão (commit) dá lugar à criação de um objeto “commit” que contém um apontador para um
instantâneo do conteúdo cujas modificações estavam indexadas no momento da submissão (conjunto de
objetos que permitem armazenar um instantâneo dos ficheiros em causa e por outro lado eu permitem
reproduzir a estrutura do repositório do projeto e dos subdiretórios), alguns metadados (autor, mensagem) e
um apontador para o objeto ”commit” anterior.
18
Git – princípios de base
19
Git – princípios de base
20
Como os comandos Git funcionam
Área de
Diretório de Repositório Repositório
encenação
trabalho Local Remoto
(stage)
git pull
git fetch
git fetch git push
Local Local
repositório local repositório local
git checkout
git add git add
edita edita
programador programador
22
Git – comandos de base
Inicializar um repositório $ git init
23
Git – comandos de base
Indexar a adição ou modificações de um ficheiro $ git add [-p] <ficheiro>
$ git rm <ficheiro>
Indexar a eliminação de um ficheiro
24
Git – comandos de base
Mostrar o detalhe de modificações não indexadas $ git diff
25
Ramos
▸ Um ramo no Git é simplesmente um ponteiro para um objeto ”
commit”. Por defeito, existe um único ramo, chamado “master”.
▸ HEAD é um ponteiro especial para o ramo para o qual estamos a
trabalhar atualmente (extraída do repositório)
26
Trabalho em equipa
Ana
João
27
Comandos para os ramos
Criar um ramo $ git branch <ramo>
28
Git - ramos
Duas formas de incluir as modificações de uma ramo num outro ramo corrente.
Redifinir a
Fusionar base (rebase)
(merge)
29
Git - ramos
▸ Fusionar as modificações de uma dado ramo no ramo corrente (HEAD)
$ git merge <ramo>
▹ Se o objeto “commit” apontado por <ramo> jà é um antepassado do objeto
”commit” corrente (HEAD), então nada é feito.
▹ Se o objeto “commit” apontado por <ramo> jà é um descendente do objeto
”commit” corrente, só o apontador do ramo corrente é movido para o
objeto “commit” abrangido pela fusão (“fast-forward”).
30
Git - ramos
31
Git - ramos
Em caso de conflito
▸ Nenhum objeto “commit” de fusão é criado, mas o processo entra em pausa.
▸ git status dá os ficheiros que não puderam ser fusionados (listados
como “unmerged”).
▸ Git adiciona marcadores de resolução de conflitos à cada ficheiro sujeito a
conflitos afim que possam ser resolvidos manualmente.
▸ Para marcar os conflitos num ficheiro <ficheiro> como resolvido, tem-se
de se fazer git add <ficheiro>. Podemos, após resolução de todos os
conflitos, submeter as modificações sob a forma de objeto “commit” de
fusão com git commit e terminar assim o processo de fusão.
32
Git - ramos
Rebasear as modificações do ramo corrente (HEAD) num dado ramo
$ git rebase <ramo>
▸ Ir ao objeto ”commit” correspondente ao antepassado mais novo comum aos dois objetos
“commit” apontados pelo ramo corrente e <ramo> .
▸ Obter e salvaguardar as mudanças introduzidas desde este ponto para cada objeto “commit”
do ramo corrente.
▸ Fazer apontar o ramo corrente para o mesmo objeto “commit” que <ramo> e reaplicar todas
as modificações uma a uma.
33
Git – trabalho com repositórios remotos
Para colaborar, é necessário comunicar com um ou mais repositórios remotos alojando o
mesmo projeto (tipicamente repositórios públicos associados à uma pessoa, uma equipa ou
todo o projeto).
35
Git – trabalho com repositórios remotos
▸ Ir buscar as modificações de um repositório remoto
36
Git – trabalho com repositórios remotos
▸ Adicionar um repositório remoto $ git remote add <nome> <URL>
37
Git – trabalho com repositórios remotos
▸ Atualizar um dado repositório remoto com um dado ramo local
$ git push <repositorio> <ramo>
Cuidado: só funciona se foi-se buscar o último objeto commit do ramo abrangido do
repositório remoto e tiver sido integrado no ramo do repositório local, i.e., se a
atualização do ramo do repositório remoto pode ser feita pelo “fast-foward”.
▸ Combinar git fetch e git merge
$ git pull <repositorio> <ramo>
▸ Combinar git fetch e git rebase
38
Git – Conselhos e boas práticas
40
Resumo
▸ O que é controlo de versões e porque devemos usá-lo.
▸ Compreender os benefícios de um sistema de controle de versão
automatizado.
▸ Compreender os princípios básicos de como funcionam os
sistemas automatizados de controle de versão.
41
Bibliografia
▸ Pro Git, Scott Chacon & Ben Straub Apress,
2014
▹ Git - Book (git-scm.com)
42
Glossário
▸ changeset / conjunto de mudanças
▹ Um grupo de mudanças num ou mais ficheiros que são ou serão adicionados à um único commit
num repositório de controle de versão.
▸ commit / confirmação
▹ Como verbo, significa registar o estado atual de um conjunto de ficheiros (um changeset) num
repositório de controle de versão. Como substantivo, designa o resultado da confirmação, ou seja,
um conjunto de alterações registado num repositório. Se um commit contém mudanças em vários
ficheiros, todas as mudanças são registadas juntas.
▸ conflict / conflito
▹ Uma alteração feita por um utilizador de um sistema de controle de versão que é incompatível com
as alterações feitas por outros utilizadores. Ajudar os utilizadores a resolver conflitos é uma das
principais tarefas do controle de versão.
43
Glossário
▸ HTTP
▹ O protocolo de transferência de hipertexto usado para partilhar páginas da web e outros
dados na World Wide Web.
▸ merge / fusão
▹ (aplicado à um repositório): Para reconciliar dois conjuntos de alterações num repositório.
▸ protocol / protocolo
▹ Um conjunto de regras que definem como um computador comunica com outro. Os
protocolos comuns na Internet incluem HTTP e SSH.
▸ remote / remoto
▹ (aplicado à um repositório) Um repositório de controle de versão conectado a outro, de
forma que ambos possam ser mantidos sincronizados trocando commits.
44
Glossário
▸ repository / repositório
▹ Uma área de armazenamento onde um sistema de controle de versão armazena o
histórico completo de commits de um projeto e informações sobre quem mudou o quê e
quando.
▸ resolve / resolver
▹ Para eliminar os conflitos entre duas ou mais alterações incompatíveis num ficheiro ou
conjunto de ficheiros geridos por um sistema de controle de versão.
▸ revision / revisão
▹ Um sinônimo para commit.
45
Glossário
▸ SHA-1
▹ SHA-1 Hashes é o método que o Git usa para processar identificadores, inclusive para commits. Para
processá-los, Git usa não apenas a mudança real de um commit, mas também os seus metadados (como
data, autor, mensagem), incluindo os identificadores de todos os commits de mudanças anteriores. Isso
torna os IDs de commit do Git virtualmente únicos. Ou seja, a probabilidade de que dois commits feitos
independentemente, mesmo com a mesma mudança, recebam o mesmo ID é extremamente pequena.
▸ SSH
▹ O protocolo Secure Shell usado para uma comunicação segura entre computadores.
▸ timestamp
▹ Um registo de quando um determinado evento ocorreu.
▸ version control / controle de versão
▹ Uma ferramenta para gerir mudanças num conjunto de ficheiros. Cada conjunto de mudanças cria um
novo commit dos ficheiros; o sistema de controle de versão permite que os utilizadores recuperem
commits antigos de forma
46
Programação Orientada por Objetos
Desenho de
aplicações
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Padrões de Desenho
2
Método verbos/substantivos
▸ Desenho de aplicações
3
Abordagem ao desenvolvimento de projetos em
POO
Documento de partida
Fase 1 Modelação
Entregáveis
4
Documento de partida
Documento de partida
Fase 1 Modelação
Entregáveis
5
Documento de partida
Modelação
Fase 1 Modelação
Entregáveis
6
Documento de partida
Modelação
Fase 1 Modelação
Entregáveis
Modelação
Fase 1 Modelação
Entregáveis
8
Documento de partida
Modelação
Fase 1 Modelação
Entregáveis
Construção e Validação
Fase 1 Modelação
Entregáveis
Construção e Validação
Fase 1 Modelação
Entregáveis
11
Documento de partida
Construção e Validação
Fase 1 Modelação
Entregáveis
▸ Construção do sistema
▹ Não tentar fazer tudo ao mesmo tempo!
▹ Definir sequência de implementação que permita ir validando incrementalmente o seu programa
▹ Exemplo:
▹ Interpretador de comandos
▹ Programa aceita comandos e dados associados, mas (ainda) não faz nada com eles
▹ Implementação de comandos
▹ Escolher uma sequência para a implementação de comandos que permita ir
testando os comandos, à medida que os implementa
12
Documento de partida
Construção e Validação
Fase 1 Modelação
Entregáveis
▸ Indicações gerais
▹ Tente ter sempre uma versão estável do seu programa o Compila sem erros
▹ Implementa algumas das funcionalidades do seu programa
▹ Está bem testada
▹ Teste as suas classes, método a método
▹ Se necessário, construa pequenos programas de teste
▹ Não avance para novas fases do desenvolvimento, sem as anteriores estarem sólidas
▹ Use sempre o melhor estilo de programação e documentação possível
13
Documento de partida
Entregáveis
Fase 1 Modelação
Entregáveis
14
Exemplo – Sistema de reservas
▸ Sistema de reserva de lugares para cinemas.
▹ O sistema de reservas do cinema deve guardar as reservas de lugares para várias salas.
▹ Cada sala tem os lugares dispostos por filas.
▹ Os clientes podem reservar os lugares e ficam com a letra da fila e o número do lugar.
▹ Eles podem solicitar a reserva de vários lugares adjacentes.
▹ Cada reserva é para uma determinada sessão (ou seja a projeção de um dado filme a uma
certa hora).
▹ As sessões têm uma data e hora e estão escalonadas para uma determinada sala.
15
Exemplo – Sistema de reservas
▸ Diagrama de classes da aplicação Sistema de reservas:
16
Exemplo – Sistema de reservas
▸ Quais são as classes da aplicação?
▹ Até agora de uma forma ou de outra tínhamos as classes da solução. Num projeto de software real
temos de encontrar essas classes, o que não é uma tarefa simples.
▹ Os passos iniciais do desenvolvimento de software são a análise e o design.
▹ Analisa-se o problema.
▹ Desenha-se a solução (o design da solução).
▹ Não existe um método bem definido e único para encontrarmos as classes da solução. Algumas
abordagens simples são:
▹ O método verbos/substantivos.
▹ A utilização de cartas CRC. 17
Método verbo/substantivo
▸ Quais são as classes da aplicação?
▹ Os substantivos descrevem “coisas”.
18
Exemplo – Sistema de reservas
▸ Verbos e substantivos
▹ O sistema de reservas do cinema deve guardar as reservas de lugares para várias salas.
▹ Cada sala tem os lugares dispostos por filas.
▹ Os clientes podem reservar os lugares e ficam com a letra da fila e o número do lugar.
▹ Eles podem solicitar a reserva de vários lugares adjacentes.
▹ Cada reserva é para uma determinada sessão (ou seja a projeção de um dado filme a uma certa hora).
▹ As sessões têm uma data e hora e estão escalonadas para uma determinada sala.
▹ O sistema guarda o número do telefone do cliente.
19
Exemplo – Sistema de reservas
▸ Verbos e substantivos
▹ O sistema de reservas do cinema deve guardar as reservas de lugares para várias salas.
▹ Os clientes podem reservar os lugares e ficam com a letra da fila e o número do lugar.
▹ Cada reserva é para uma determinada sessão (ou seja a projeção de um dado filme a uma certa hora).
▹ As sessões têm uma data e hora e estão escalonadas para uma determinada sala.
21
Exemplo – Sistema de reservas
▸ Verbos e substantivos
▹ O sistema de reservas do cinema deve guardar as reservas de lugares para várias salas.
▹ Os clientes podem reservar os lugares e ficam com a letra da fila e o número do lugar.
▹ Cada reserva é para uma determinada sessão (ou seja a projeção de um dado filme a uma certa hora).
▹ As sessões têm uma data e hora e estão escalonadas para uma determinada sala.
Sessão Lugar
Escalonada para (sala)
23
Cartas CRC e
Cenários
Desenho de aplicações
24
Cartas CRC
▸ Cartas CRC
▹ CRC significa:
▹ C – Classes
▹ R – Responsabilidades
▹ C - Colaboradores
26
Cenários
▸ Cenários
▹ Depois de se obterem as possíveis classes do sistema e que são identificadas nas
cartas CRC é necessário descobrir as interações entre elas e isso será feito através
de Cenários.
▹ Um cenário descreve um caso concreto da realização de uma atividade no sistema.
▹ Vamos identificar o que se faz (em cada classe) quando se utiliza o sistema.
▹ É uma forma de encontrar as interações entre objetos (colaborações).
27
Cenários – exemplo prático
SistemaReservas Colaboradores
Pode encontrar as sessões Sessão
pelo título do filme e pelo
dia
Obtém e mostra os
detalhes das sessões
28
Cenários
▸ Cenários
▹ Os cenários permitem verificar se a descrição do problema é
clara e se está completa.
▹ É necessário perder algum tempo a encontrar os vários cenários
de utilização.
▹ A análise efetuada do problema leva-nos à solução
▹ Se encontrarmos os erros e omissões nesta fase estaremos
a poupar tempo e esforço desperdiçados mais tarde.
29
Desenho de classes
▸ Desenho de classes
▹ A análise dos cenários ajuda a clarificar a estrutura da aplicação
▹ Cada carta está relacionada com uma classe
▹ As colaborações revelam a cooperação entre classes/interação
entre objetos.
▹ As responsabilidades revelam métodos públicos.
▹ E algumas vezes atributos; por exemplo: “guarda coleções...”
30
Desenho de classes
▸ Desenho de classes
▹ As responsabilidades devem ser atribuídas/implementadas
seguindo os princípios do desenho de classes estudado
anteriormente:
▹ Coesão
▹ Acoplamento
▹ Desenho Orientado por responsabilidades
31
Coesão
▸ A coesão é o princípio Orientado a Objetos que visa garantir que uma classe é
concebida com um propósito único e bem focado.
▸ Quanto mais focada for uma classe, maior é a coesão dessa classe.
▸ Vantagens da alta coesão
▹ mais fáceis de manter (e mudam com menos frequência) do que as
classes com baixa coesão.
▹ Classes mais reutilizáveis do que outras classes.
32
Coesão
▸ Exemplo:
▹
class Multiply {
Suponha que temos uma classe que multiplica
dois números, mas a mesma classe cria uma public int multiply(int num1, int num2)
{
janela pop-up que mostra o resultado. return num1 * num2;
33
Acoplamento
▸ Na orientação a objetos, o acoplamento se refere ao grau de conhecimento direto que
um elemento tem de outro. Em outras palavras, com que frequência as mudanças na
classe A forçam mudanças relacionadas na classe B.
▸ Existem dois tipos de acoplamento:
▹ Acoplamento rígido: em geral, o acoplamento rígido significa que as duas
classes frequentemente mudam juntas. Em outras palavras, se A sabe mais do
que deveria sobre a maneira como B foi implementado, então A e B estão
fortemente acoplados.
▹ Exemplo: se quiser mudar de pele, também terá que mudar de corpo
porque os dois estão unidos - eles estão fortemente acoplados.
34
Acoplamento
▸ Acoplamento fraco: o acoplamento fraco significa que as classes são em sua maioria
independentes. Se o único conhecimento que a classe A tem sobre a classe B é o que a
classe B expôs por meio da sua interface, então diz-se que a classe A e a classe B
estão fracamente acopladas.
▹ Exemplo: se quiser trocar de camisa, não será forçado a trocar de corpo -
quando se pode fazer isso, o acoplamento é fraco. Quando não se pode fazer
isso, tem um acoplamento forte.
35
Acoplamento
▸ Qual o melhor?
▹ Em geral, o acoplamento rígido é pior, porque
▹ reduz a flexibilidade e a reutilização do código,
▹ torna as mudanças muito mais difíceis,
▹ impede a capacidade de teste etc.
▹ O acoplamento fraco é melhor quando é necessário mudar ou fazer
crescer uma aplicação.
▹ apenas algumas partes da aplicação devem ser afetadas quando os
requisitos mudam.
36
“ Uma classe deve ter
apenas um motivo para
mudar.
37
PRINCÍPIO DE RESPONSABILIDADE
ÚNICA
▸ Conceito muito simples de explicar, porém difícil de implementar.
▸ No contexto do Princípio da Responsabilidade Única, a responsabilidade é definida como
um motivo para a mudança.
▸ Seguindo o princípio de responsabilidade única, garante-se que uma classe ou módulo
tenha alta coesão, o que significa que a classe não faz mais do que o que deveria fazer.
▸ Em suma, uma razão única para mudar.
▸ Se, pelo contrário, constrói-se uma classe com mais de uma responsabilidade, o que se
está a fazer é comprometer-se com essas responsabilidades.
▹ leva a um design que é frágil e difícil de manter, com tudo o que isso acarreta.
38
PRINCÍPIO DE RESPONSABILIDADE
ÚNICA
39
Desenho da interface das classes
▸ Desenho da interface das classes
▹ Depois de encontrar as classes, responsabilidades e colaboradores é
ainda necessário traduzir as descrições informais para chamada de
métodos e parâmetros dos mesmos.
▹ Repetir a análise de cenários tendo em conta agora as chamadas
de métodos, passagem de parâmetros e valores de retorno.
▹ Anotar as assinaturas dos métodos obtidas.
▹ Criar a estrutura das classes com os métodos públicos ainda sem o
código interno.
▹ Um desenho cuidadoso é a chave do sucesso da implementação.
40
Outros Aspetos do
desenvolvimento
Desenho de aplicações
41
Documentação
▸ Documentação
▸ Trabalho de equipa
43
Protótipos
▸ Prototipagem
▹ Devem-se construir protótipos da aplicação.
▹ Os protótipos são versões da aplicação onde uma parte é simulada para que se
possa experimentar com outras partes.
▹ Os protótipos ajudam no inicio na análise do sistema.
▹ Permitem uma identificação inicial do problema.
▹ Os componentes ainda incompletos podem ser simulados.
▹ Por exemplo retornando valores fixos.
▹ É de evitar comportamentos aleatórios que são difíceis de prever.
44
Desenvolvimento de software
▸ O modelo Waterfall
▹ Análise
▹ Design
▹ Implementação
▹ Testes unitários e de integração
▹ Instalação
▸ É o modelo de desenvolvimento mais conhecido e tradicional.
▹ Não é o mais usado.
▹ Parte do princípio que os programadores conhecem à partida todas as
funcionalidades em detalhe e que o sistema não será alterado depois de entregue.
45
Desenvolvimento de software
▸ O modelo Iterativo
▸ Baseia-se em prototipagem, interações com o cliente e pequenos ciclos de
desenvolvimento iterativos e incrementais
▹ Iterações com:
▹ Análise
▹ Design
▹ Protótipo
▹ Feedback do cliente
▸ É, talvez, o modelo de desenvolvimento mais comum atualmente.
▹ É um modelo mais realístico.
▹ O software vai crescendo em vez de ser desenhado.
46
Padrões de
Desenho
Desenho de aplicações
47
Utilização de padrões de desenho
▸ Tendo em conta que:
▹ As relações entre classes são bastante importantes e podem ser complexas.
▹ São problemas estudados com boas soluções que são exemplos de boas práticas no desenvolvimento de software.
▹ São descritos com base numa estrutura (tal como as cartas CRC) e que foi inicialmente usada no campo da arquitetura. 48
Estrutura dos padrões de desenho
▸ Software Design Patterns:
▹ Nome do padrão
▹ Problema abordado pelo padrão
▹ Como é proposta a solução
▹ Estrutura
▹ Participantes
▹ Colaborações
▹ Consequências da solução
▹ Resultados e compromissos
49
Padrão Singleton
▸ É um padrão criacional.
▹ Lida com o problema de existir apenas uma única instância de uma dada classe.
▸ Todos os clientes utilizam o mesmo objeto.
▸ A solução neste caso é tornar o construtor privado para impedir que se criem objetos
externamente.
▸ É obtida a única instância existente através de um método estático getInstance()
▸ Exemplo: A classe Canvas de um objeto Shape.
50
Exemplo –
Padrão Singleton
51
Padrão Decorator
▸ É um padrão estrutural.
▹ Lida com o problema de adicionar funcionalidade a um objeto existente sem utilizar a herança
de classes.
▸ Os clientes deste padrão requerem um objeto de um determinado tipo (uma interface ou uma
superclasse) mas com funcionalidades extra.
▸ A solução é criar um objeto que inclui (wraps) o objeto que se pretende utilizar e que será utilizado
em vez do original.
▹ O novo objeto inclui a funcionalidade que se pretende invocando-a diretamente no objeto
incluído e adicionalmente tem os métodos que aumentam a sua funcionalidade.
▸ Exemplo: A classe BufferedReader é um Decorator da classe Reader.
▹ Pode ser usada em vez da classe Reader porque inclui a mesma funcionalidade mas tem um
comportamento adicional ao da classe original.
52
Padrão Factory Method
▸ É um padrão criacional.
▹ Lida com o problema da criação de um objeto sem especificar concretamente qual a
classe que vai ser utilizada.
▸ Os clientes deste padrão requerem um objeto de um determinado tipo: de uma dada
interface ou superclasse.
▸ A solução é criar um método que tem liberdade para devolver um objeto de qualquer
classe que implemente essa interface ou que seja derivado dessa superclasse.
▹ O tipo exato do objeto depende do contexto.
▸ Exemplo: Os métodos iterator das classes de coleção.
53
Padrão Observer
▸ É um padrão comportamental.
▹ Lida com o problema de separar o modelo interno de uma vista desse modelo.
▸ Define uma relação de um para muitos entre objetos.
▸ O objeto observado notifica todos os objetos observadores de qualquer alteração no seu estado.
▸ Uma classe ou um conjunto de classes incluem a lógica e os dados do programa e permitem a existência de
observadores desses dados. Depois são criadas visualizações independentes da lógica que são atualizadas
sempre que mudam os dados.
55
Bibliografia
56
Programação Orientada por Objetos
Testes
▸ Testes
2
A aplicação CityAssets
câmara Municipal
▸ Deve poder:
▹ Mostrar o número de bens
▹ Calcular o custo mensal de manutenção dos bens
▹ Apresentar a informação de um dado bem
3
Ideias para a solução...
Collections Framework
4
E se houver erros?
5
Como lidar com erros?
6
Processo de desenvolvimento
Análise Determinar
objetivos
Desenho
Planear a Identificar e
Implementação iteração
seguinte
resolver
riscos
Verificação
Desenvolver
e testar
Evolução
7
Como garantir a qualidade do software
8
Várias técnicas para verificação da qualidade
▸ ...
9
Testes unitários
▸ Focam-se numa parte específica da funcionalidade a que neste contexto vamos chamar
unidades
▹ Métodos
▹ Classes
11
Exemplo
Crie um caso de teste
13
Vista do projeto
seletores.
▹ Na prática, como vamos ver mais a frente, nem sempre é necessário testar
seletores 15
Quando criamos um novo bem
16
Correr o teste
▸ Para verificar que ao número de bens criados é mesmo 1
Barra verde
significa que
todos os testes
passaram
(podem ser
milhares)
17
Experimente “estragar o teste”, admitindo que o
número de testes deveria ser 2
Barra vermelha
significa que pelo
menos um teste
falhou (podem
ser milhares)
18
O método assertEquals()
19
Outro teste...
@Test
public void testToString() {
Asset asset = new Asset(15000.00,155.55);
assertEquals("Capital 15000.00 € - custo mensal 155.55 €",asset.toString());
}
20
Construção do método de teste
▸ Criar o objeto e colocá-lo num estado conhecido
▸ Invocar um método que retorna o resultado “real”
▸ Construir o resultado esperado
▸ Invocar:
assertEquals(valorEsperado, valorReal)
22
Test-Driven Development - TDD
Desenvolvimento
dirigido pelos testes
Nova
Melhorar código
Desenvolvimento e voltar a testar
funcionalidade:
escrever um
teste para ela
dirigido pelos testes
Correr todos os Compilar. Erros:
testes. Todos o teste refere-
devem se a coisas que
(continuar a) ainda não
passar. existem
Escrever código
Corrigir erros de
que faz o teste
passar compilação
Correr todos os
testes. O teste
acabado de criar
deve falhar
24
Desenvolvimento dirigido pelos testes
▸ Os testes dirigem o processo
▹ Antes de acrescentar funcionalidade, escrever um teste
▹ Depois de falhar o teste, acrescentamos a funcionalidade
▸ O que ganhamos com este processo?
▹ Controlo sobre o processo de desenvolvimento
▸ Princípios fundamentais:
▹ Nunca estar a mais de um teste de distância da barra verde
▹ Nunca escrever novo teste quando se está com a barra vermelha
▹ Correr todos os testes frequentemente (pelo menos uma vez por manhã ou tarde, de
preferência várias)
25
Funcionamento dos testes de unidade
Exemplo
A aplicação CityAssets
▸ Por uma questão de transparência para com os seus cidadãos, uma cidade
decide conceber um sistema informático que lhe permita representar
todos os bens (edifício, veículo,...) que possui.
▸ Um bem é definido pelo seu valor e custo mensal de manutenção. Também
queremos saber o número de instâncias de cada bem.
▸ Para o mini sistema de informação que estamos a desenvolver, uma
cidade pode ser considerada como uma classe de objetos que referencia
todos os bens que possui. Esta classe deve oferecer os seguintes serviços:
– Consultar a informação de um determinado imóvel, – Calcular o custo
mensal total de manutenção dos bens,
28
Comecemos pela classe Asset (Esqueleto)
30
Regras específicas do TDD
▸ Comecemos pelo construtor, dado que sem ele não vamos conseguir fazer mais
nada
▸ Acrescente um teste simples ao construtor
▹ Sim, esse mesmo, que ainda não desenvolveu
31
Vários erros de compilação
32
Na classe Asset, falta o construtor
33
Vamos testar...
34
Transformemos o teste para ser mais geral
▸ Só podemos avançar para o próximo teste depois de correr com sucesso este
35
Vamos corrigir o código da classe Asset
36
Primeiro, construímos o novo teste
37
Este código é suficiente para passar o teste (e errado, claro)
38
Temos de criar um teste em que o código não passe
@Test
public void testToString(){
Asset asset = new Asset(15000.0,155.55,1);
39
Agora, alteramos o código, para passar no teste
@Override
public String toString(){
return "" + "Capital " + value +
" € - custo mensal " + manutentionCost + " € - " +
numberOfInstances + " Instância(s).";
}
40
Testar o seletor do número de bens
@Test
public void testgetNumberOfInstances(){
asset = new Asset(6700.0,29.0,2);
assertEquals(2,asset.getNumberOfInstances());
}
41
Agora, alteramos o código, para passar no teste
42
Definir uma fixture
public class AssetTest @Test
{ public void testToString(){
Asset asset, asset2; assertEquals("Capital 15000.0 € - custo mensal 155.55 € - 1
Instância(s).",asset.toString());
public AssetTest()
assertEquals("Capital 6700.0 € - custo mensal 29.0 € - 3
{
Instância(s).",asset2.toString());
asset = new Asset(15000.0,155.55);
}
asset2 = new Asset(6700.0,29.0);
}
@Test
public void testSimpleConstructor(){
public int getNumberOfInstances()
assertEquals(15000.0, asset.getValue());
{
assertEquals(155.55, asset.getManutentionCost());
return numberOfInstances;
}
}
43
Para quê fazer código incompleto até ter testes que o detectem?
44
Podemos agora melhorar o código
▸ Atividade conhecida como refabricação (refactoring)
▹ Devemos aperfeiçoar código que esteja a funcionar
▹ Melhorando a sua estrutura interna
▹ Sempre sem alterar o seu comportamento externo
▹ Para quê?
▹ Tornar o código fonte tão fácil de compreender quanto possível
▹ Preparar código para facilitar adição de novas funcionalidades
▹ Mas isto não tem riscos?
▹ Pode haver regressões, i.e., podemos inadvertidamente introduzir bugs em código que estava a
funcionar bem
▹ Porisso, éfundamental ter testesquedetetemessesbugsque podemosinadvertidamenteintroduzir durante as
modificações
45
Algumas regras no desenvolvimento guiado por testes
46
Exemplo de refabricação
49
Vale a pena testar um seletor?
▸ Depende...
▹ Se o seletor se limita a retornar o valor de um campo, o teste é uma
perda de tempo
▹ Estes métodos podem ser simples demais para poder falhar por si só
@Override
public String getName() {
return this.name;
}
51
Testar modificadores
52
Vale a pena testar um modificador?
▸ Depende...
▹ Se o modificador se limita a afetar o valor de um campo, por cópia de um argumento, ou algo de
simplicidade equivalente, o teste pode ser uma perda de tempo
▹ Estes métodos podem ser simples demais para poder falhar por si só
@Override
public void setName(String name)
{
this.name = name;
}
Ø Em todo o caso, pode testar estes métodos indiretamente, recorrendo aos seletores
Ø Se o modificador faz algo mais complexo, vale a pena testar o modificador
53
Testar operações sobre coleções
▸ Operações que visitam a coleção para recolher (acumular, filtrar, ...) informação
54
Operações que modificam a coleção
▸ Reordenações
55
Operações que visitam a
coleção para recolher
informação
56
Esquelete da classe Assets
/**
* Um conjunto de bens
*
* @author Cédric Grueau
public String getInfo(int indice)
* @version marco 2022
{
*/
}
import java.util.ArrayList;
public ArrayList<Asset> getAssets(){
public class Assets
}
{
ArrayList<Asset> assets;
public void removeAssets(Asset[] assets){
/**
}
* Constructor for objects of class Assets
public int size(){
*
* @param assets um array de bens
}
*/
}
public Assets(Asset[] assets)
{
}
57
Esquelete da classe Assets, versão “compilável”
/**
* Um conjunto de bens
*
* @author Cédric Grueau
public String getInfo(int indice)
* @version marco 2022
{
*/
return null;
}
import java.util.ArrayList;
public ArrayList<Asset> getAssets(){
public class Assets
return null;
{
}
ArrayList<Asset> assets;
public void removeAssets(Asset[] assets){
/**
* Constructor for objects of class Assets
}
*
public int size(){
* @param assets um array de bens
return 0;
*/
}
public Assets(Asset[] assets)
}
{
}
58
Teste de Assets(Asset[] assets)
public class AssetsTest
{
private Asset[] someAssets =
{new Asset(130.0,0.0,10),new Asset(3500.0,250.0,5),
new Asset(39000.0,1000.0,1)};
private Assets assets;
Começamos por declarar variáveis de instância para
os nossos testes.
public AssetsTest(){}
@Test
public void testConstructor() {
System.out.println("Teste do construtor");
assertEquals(3, assets.size());
}
59
Teste à operação Assets(Asset[] assets)
▸ O teste falha, porque o
construtor e o método size
ainda tem a implementação por
omissão
60
Implementação de Assets(Asset[] assets)
61
Implementação de size()
62
Teste de getInfo(int indice)
@Test
public void testGetInfo(){
assertEquals("Capital 3500.0 € - custo mensal 250.0 € - 5 Instância(s).",assets.getInfo(1));
}
63
Implementação de getInfo(int indice)
64
Resumo
q Definição
q Processo de teste
65
Bibliografia
66
Instruções de afirmação do JUnit
▸ Boolean
▸ Assert Equals
▹ assertTrue(condition)
▹ assertEquals(expected, actual)
▹ assertFalse(condition)
▸ Assert Array Equals
▸ Null object
▹ assertArrayEquals(expected, actual)
▹ assertNull(object)
▹ assertEquals(expected[i],actual[i])
▹ assertNotNull(object)
▹ assertArrayEquals(expected[i],actual[i])
▸ Identical
▹ assertSame(expected, actual)
▹ assertNotSame(expected, actual)
67
Exemplos de utilização de instruções de afirmações
@Test
public void testAssert(){ //instruções de
assertEquals(string1,string2);
//Declaração de variáveis
String string1="Junit"; assertSame(string3, string4);
68
O que é o teste de software?
69
Implicações da definição de teste
70
Processo de teste (Modelo em V estendido)
Execute acceptance
tests
Specify Execute
Requirements system tests
Requirements System/acceptance
review test plan & test cases
review/audit
Specify/Design
Code System/
acceptance tests Execute integration
Design
tests
Integration
Design review
test plan & test cases
review/audit
Specify/Design Code
Integration tests
Code Execute
unit tests
Unit
Code reviews test plan & test cases
review/audit
Specify/Design Code (source: I. Burnstein, pg.15)
Unit tests
71
Fases de teste – Teste Unitário
73
Fases de teste – Testes de sistema
74
Fases de teste – Testes de Aceitação
76
Testes
77
Programação Orientada por Objetos
Iteradores
▸ Método equals
2
A aplicação PlayList - continuação
Municipal
▸ Deve poder:
▹ Mostrar o número de bens
▹ Calcular o custo mensal de manutenção dos bens
▹ Apresentar a informação de um dado bem
3
Implementação parcial da classe Assets
import java.util.ArrayList;
@Test
public void testRemoveAssets() {
System.out.println("Teste de remoção de bens");
assets.removeAssets(ASSETS_TO_REMOVE);
assertEquals(1, assets.size());
}
5
Implementação de removeAssets(Asset[] assets)
8
Implementação de removeAssets(Asset[] assets)
while(iterator.hasNext()) {
usar o objeto
}
11
Percorrer coleções com Iteradores
▸ Funcionamento do iterador
myList.iterator()
myList:List
Inicialmente é como se o
:Iterator iterador estivesse antes do
primeiro elemento da lista.
12
Percorrer coleções com Iteradores
▸ Funcionamento do iterador myList.iterator()
myList:List hasNext()?
:Element
next()
Vai buscar o
:Iterator próximo elemento e
avança o iterador
Element e = iterator.next();
13
Percorrer coleções com Iteradores
▸ Funcionamento do iterador myList.iterator()
myList:List hasNext()?
:Element
next()
:Iterator
Element e = iterator.next();
14
Percorrer coleções com Iteradores
▸ Funcionamento do iterador myList.iterator()
myList:List hasNext()?
:Element
next()
:Iterator
Element e = iterator.next(); 15
Percorrer coleções com Iteradores
▸ Funcionamento do iterador myList.iterator()
myList:List hasNext()?
:Element
Não existem
mais
elementos.
:Element :Element :Element Terminou a
operação.
:Iterator
16
Implementação de removeAssets(Asset[] assets)
▸ Com um iterador
17
Índices versus Iteradores
▸ Formas de percorrer (iterar) uma coleção
▹ Ciclo for
▹ Usado quando é útil usar os índices ao percorrer-se a coleção.
▹ Usado em repetições que não envolvem coleções e que se repetem um determinado número de vezes
▹ Ciclo for-each
▹ Usado quando se pretende percorrer todos os elementos da coleção.
▹ Ciclo while
▹ Usado para percorrer os elementos da coleção quando se pretende interromper a meio.
▹ Usado em repetições que não envolvem coleções e em que não se sabe determinar o número de vezes que se
irá repetir.
▹ Objeto iterator
▹ Usado para percorrer os elementos da coleção quando se pretende interromper a meio.
▹ Usado em coleções que não usam índices
▹ Usado quando se pretendem remover elementos da coleção
18
Bibliografia
19
Programação Orientada por Objetos
Introdução às
Coleções
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Expressões lambda
2
Exemplo – Monitorização de animais
▸ Requisitos da aplicação:
▹ Sistema de monitorização de populações animais.
▹ Processa relatórios dos avistamentos de animais enviados
por vários observadores.
▹ Cada relatório consiste no nome e número de animais
avistados, quem enviou o relatório (um inteiro), a área da
observação (um inteiro) e a altura em que foi feita a
observação (um inteiro representando o número de dias
desde o inicio da monitorização)
3
Exemplo – Monitorização de animais
4
Exemplo – Monitorização de animais
▸ Classes da aplicação:
▹ Sighting
▹ Relatório da observação.
▹ SightingReader
▹ Usada para ler uma lista de
observações a partir de um ficheiro.
▹ AnimalMonitor
▹ Faz o processamento de relatórios de
observações.
5
Exemplo – Monitorização de animais
▸ Representação da
public class Sighting {
private String animal;
observação – classe
private int spotter; // observador
private int count;
private int area;
Sighting private int period;
6
Exemplo – Monitorização de animais
public String getAnimal() {
return animal;
}
7
Exemplo – Monitorização de animais
8
Exemplo – Monitorização de animais
Não precisamos de
saber os detalhes de
implementação
9
Exemplo – Monitorização de animais
public class AnimalMonitor {
▸ Processamento das
private ArrayList<Sighting> sightings;
public AnimalMonitor() {
observações – classe this.sightings = new ArrayList<>();
}
AnimalMonitor
public void addSightings(String filename) {
SightingReader reader = new SightingReader();
sightings.addAll(reader.getSightings(filename));
}
// restantes métodos
Lê a lista de }
observações e
adiciona-a à lista
sightings
10
Exemplo – Monitorização de animais
O que faz?
11
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor public void printList() {
– método printList
for(Sighting record : sightings) {
System.out.println(record.getDetails());
}
Mostra todas as
observações
12
Exemplo – Monitorização de animais
13
Exemplo – Monitorização de animais
– método
for(Sighting record : sightings) {
printSightingsOf
if(animal.equals(record.getAnimal())) {
System.out.println(record.getDetails());
}
}
}
Mostra apenas as
observações de
um dado animal
14
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor
– método ???????? public void ????????(int spotter) {
15
Exemplo – Monitorização de animais
Mostra as
observações feitas
por um dado
observador
16
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor public int ????????(String animal) {
– método ???????? int total = 0;
for(Sighting sighting : sightings) {
if(animal.equals(sighting.getAnimal())) {
total = total + sighting.getCount();
}
}
return total;
}
O que faz?
17
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor
public int getCount(String animal) {
– método getCount
int total = 0;
for(Sighting sighting : sightings) {
if(animal.equals(sighting.getAnimal())) {
total = total + sighting.getCount();
}
}
Retorna o total de return total;
observações de }
um dado animal
18
Exemplo – Monitorização de animais
O que faz?
19
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor
– método public void printEndangered(ArrayList<String> animalNames,
int dangerThreshold) {
printEndangered
for(String animal : animalNames) {
if(getCount(animal) <= dangerThreshold) {
System.out.println(animal + " is endangered.");
}
}
20
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor
public void ????????() {
– método ????????
Iterator<Sighting> it = sightings.iterator();
while(it.hasNext()) {
Sighting record = it.next();
if(record.getCount() == 0) {
it.remove();
}
}
}
O que faz?
21
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor public void removeZeroCounts() {
– método
Iterator<Sighting> it = sightings.iterator();
removeZeroCounts
while(it.hasNext()) {
Sighting record = it.next();
if(record.getCount() == 0) {
it.remove();
}
Elimina todos os }
relatórios cujo }
número de animais
avistados é 0.
22
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor public ArrayList<Sighting> ????????(String animal, int area) {
23
Exemplo – Monitorização de animais
public ArrayList<Sighting> getSightingsInArea(String animal, int area) {
▸ Classe AnimalMonitor – ArrayList<Sighting> records = new ArrayList<>();
getSightingsInArea if(animal.equals(record.getAnimal())) {
if(record.getArea() == area) {
records.add(record);
}
}
}
return records;
Retorna uma lista de
observações de um }
animal especificado
numa dada área.
24
Exemplo – Monitorização de animais
25
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor public ArrayList<Sighting> getSightingsOf(String animal) {
– método
getSightingsOf ArrayList<Sighting> filtered = new ArrayList<>();
for(Sighting record : sightings) {
if(animal.equals(record.getAnimal())) {
filtered.add(record);
}
}
Filtra as observações, return filtered;
retornando uma lista apenas }
com os relatórios de um
dado animal.
26
Processamento Imperativo de Coleções
▸ Processamento imperativo de coleções
▹ Todos os processamentos de coleções feitos até agora utilizaram um paradigma de
programação imperativo.
▹ Consistiam num ciclo que ia obter cada um dos elementos da coleção e efetuava
uma determinada ação com esse elemento.
A estrutura deste processamento era semelhante a:
28
Processamento Funcional de Coleções
Coleção.fazIstoParaCadaElemento(pedaço de código)
printList: }
// Com expressões lambda:
public void printList() {
sightings.forEach(
(Sighting record) -> {
System.out.println(record.getDetails());
Já não aparece }
o ciclo
);
}
33
Expressões Lambda Simplificação
1
Simplificações System.out.println(record.getDetails());
}
1. O tipo do parâmetro pode ser
);
omitido uma vez que o
compilador consegue }
determiná-lo: é o mesmo que
o tipo dos elementos da
coleção.
34
Expressões Lambda
▸ Expressões lambda – Exemplo
com o método printList: // Com expressões lambda:
Simplificação
public void printList() {
2
sightings.forEach(
record -> {
Simplificações System.out.println(record.getDetails());
2. Se existir apenas um }
);
parâmetro não é
necessário colocar os }
parênteses.
35
Expressões Lambda
▸ Expressões lambda – Exemplo
Simplificação
com o método printList: // Com expressões lambda:
3
public void printList() {
sightings.forEach(
record -> System.out.println(record.getDetails())
Simplificações );
instrução no corpo do
lambda não é necessário
usar chavetas, nem colocar
o ponto e vírgula final.
36
Expressões Lambda
public void printList() {
▸ Expressões lambda – for(Sighting record : sightings) {
Exemplo com o método System.out.println(record.getDetails());
}
printList:
}
// Com expressões lambda: Mais simples!
public void printList() {
sightings.forEach(record ->
System.out.println(record.getDetails()));
}
37
Expressões Lambda
Símbolo ->
▸ Sintaxe de uma expressão
lambda
record -> System.out.println(record.getDetails())
Parâmetro(s) de
entrada(s) Instrução(ões) para execução
38
Streams
▸ Conceito de stream
▹ O java 8 introduziu o conceito alargado de stream que é entendido como uma coleção mas com
características especiais:
▹ Os elementos de uma stream não são acedidos por um índice mas sim sequencialmente.
▹ O conteúdo e a ordenação de uma stream não pode ser alterado.
▹ Neste caso ter-se-ia que criar uma nova stream
▹ Uma stream pode ser potencialmente infinita!
▹ Por exemplo o processamento de mensagens oriundas de uma rede social
▹ É utilizado para unificar o processamento de conjuntos de dados independentemente da sua origem.
▹ O método forEach da classe ArrayList é um exemplo de um método que utiliza a noção de
stream.
39
Streams
▸ Conceito de stream
▹ Algumas classes como a classe ArrayList, e outras classes de coleção,
disponibilizam um método stream que retorna uma stream com os
elementos da coleção por ordem dos seus índices.
▹ As operações habituais em coleções podem ser feitas através de streams
sem necessidade de utilizar ciclos. Estas operações utilizam expressões
lambda.
▹ Iremos estudar as operações de filtragem (filter), mapeamento (map)
e redução (reduce) utilizadas em steams.
40
Streams: o método filter
▸ O método filter
▹ Este método recebe uma stream,
seleciona alguns dos seus
elementos e cria uma nova stream
apenas com os elementos
selecionados
▹ Diz-se que aplicamos um filtro à
stream. Um exemplo poderia
ser a seleção de todos os
relatórios do animal “elefante”.
41
Streams: o método map
▸ O método map
▹ Este método recebe uma stream e cria
uma nova stream onde os elementos
iniciais são mapeados (transformados)
noutros elementos
▹ Um exemplo poderia ser substituir
cada objeto Sighting da coleção inicial
pelo número de animais observados
em cada um deles.
42
Streams: o método reduce
▸ O método reduce
▹ Este método recebe uma stream e reduz
todos os elementos a um único valor.
▹ Um exemplo poderia ser termos o
número de todos os elefantes
observados e depois somarmos tudo.
É um valor único com a soma de
todos.
43
Streams: pipelines
▸ Pipelines
▹ As streams e os seus métodos tornam-se mais úteis se os pudermos juntar como uma
sequência de operações. É esse o conceito de pipelines.
▹ Por exemplo queremos saber quantos avistamentos de elefantes foram registados:
1. Filtramos a coleção de relatórios para obtermos apenas os relatórios
respeitantes a elefantes.
2. Mapeamos cada relatório obtido (um objeto da classe Sighting) no número de
animais que está nesse relatório.
3. Reduzimos a um único valor que corresponde à soma de todos os números de
animais obtidos anteriormente.
44
Streams: pipelines
▸ Pipelines
▹ Quantos avistamentos de elefantes foram registados:
1. Filtramos a coleção de relatórios para obtermos apenas os relatórios respeitantes a elefantes.
2. Mapeamos cada relatório obtido (um objeto da classe Sighting) no número de animais que está nesse relatório.
3. Reduzimos a um único valor que corresponde à soma de todos os números de animais obtidos anteriormente.
45
Streams: o método filter
Método filter
▸ Cria um subconjunto (filtrado) da coleção
inicial. public void printSightingsOf(String animal) {
46
Streams: o método filter
Método filter
Obtém o número de
avistamentos por relatório Soma os todos os números de
avistamentos
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
49
Streams: o método reduce
O método reduce
▸ Recebe uma stream e reduz todos
os elementos a um único valor. public int getCount(String animal) {
Os parâmetros do método }
reduce são um pouco mais
complicados!
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
50
Streams: o método reduce
O método reduce
▸ Recebe uma stream e reduz todos os elementos a um único valor.
▹ Exemplo. Contar todos os animais de um determinado tipo.
return sightings.stream()
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
51
Exemplo – Monitorização de animais
▸ Processamento funcional das observações – nova classe AnimalMonitor
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
52
Exemplo – Monitorização de animais
Classe AnimalMonitor – método public void printList() {
printList for(Sighting record : sightings) {
System.out.println(record.getDetails());
}
}
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
53
Exemplo – Monitorização de animais
Classe AnimalMonitor – método public void printSightingsOf(String animal) {
printSightingsOf for(Sighting record : sightings) {
if(animal.equals(record.getAnimal())) {
System.out.println(record.getDetails());
}
}
}
public void printSightingsOf(String animal) {
sightings.stream()
Nova classe AnimalMonitor – método
.filter(sighting -> animal.equals(sighting.getAnimal()))
printSightingsOf .forEach(sighting -> System.out.println(sighting.getDetails()));
}
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
54
Exemplo – Monitorização de animais
Classe AnimalMonitor – método public void printSightingsBy(int spotter) {
for(Sighting record : sightings) {
printSightingsBy if(record.getSpotter() == spotter) {
System.out.println(record.getDetails());
}
}
}
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
55
Exemplo – Monitorização de animais
public int getCount(String animal) {
Classe AnimalMonitor – int total = 0;
for(Sighting sighting : sightings) {
método getCount if(animal.equals(sighting.getAnimal())) {
total = total + sighting.getCount();
}
}
return total;
}
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
56
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor –
método removeZeroCounts public void removeZeroCounts() {
Iterator<Sighting> it = sightings.iterator();
while(it.hasNext()) {
Sighting record = it.next();
if(record.getCount() == 0) {
Também é possível
it.remove();
com coleções usando o
método removeIf }
parecido com o }
forEach. }
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
57
Exemplo – Monitorização de animais
▸ Classe AnimalMonitor
– método public void removeZeroCounts() {
removeZeroCounts sightings.removeIf(sighting -> sighting.getCount() == 0));
Condição de
remoção do
elemento
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
58
Streams
▸ Streams
▹ Alguns dos métodos usados pelas streams em pipelines são considerados intermediários,
enquanto outros são terminais.
▹ Os métodos intermediários devolvem streams e podem ser seguidos por outros métodos.
▹ Por exemplo map e filter.
▹ Os métodos terminais não podem ser seguidos por outros métodos de stream porque não
devolvem streams ou porque não devolvem nada (são void).
▹ Por exemplo reduce.
▹ As streams têm mais métodos para além dos estudados aqui (filter, map e reduce) que podem
ser consultados na documentação oficial e que pemitem outras operações.
▹ Por exemplo count, limit, findfirst, skip, etc.:
59
Operador de resolução de escopo em Java
60
Operador de referência de método em java
61
Operador de referência de método: exemplo
import java.util.stream.*;
public class LambdaExpressionExample {
▸ Alternativa
Prof. José Cordeiro – Prof. José Sena Pereira – Prof. Cédric Grueau
64
Programação Orientada por Objetos
Herança
▸ Herança de classes
▸ Hierarquias de classes
▸ Principio da substituição
2
Exemplo – Rede Social
▸ Requisitos da rede social:
▹ Um pequeno protótipo com a base para o armazenamento e
apresentação de mensagens.
3
Exemplo – Rede Social
▸ Objetos que pretendemos representar: MessagePost e PhotoPost
4
Exemplo – Rede Social
▸ Classes associadas: MessagePost e PhotoPost
Atributos
Métodos
5
Exemplo – Rede Social
▸ Diagrama de objetos da rede social
6
Exemplo – Rede Social
▸ Diagrama de classes da rede social
7
Exemplo – Rede Social
▸ Classe MessagePost public class MessagePost {
// continua…
currentTimeMillis ???
8
(System.currentTimeMillis – das bibliotecas do Java)
9
Exemplo – Rede Social
▸ Métodos da classe public void like() {
likes++;
}
MessagePost (1/3) public void unlike() {
if (likes > 0) {
likes--;
}
}
10
Exemplo – Rede Social
public void display() {
System.out.println(username);
System.out.println(message);
System.out.print(timeString(timestamp));
if(comments.isEmpty()) {
System.out.println(" No comments.");
}
else {
System.out.println(" " + comments.size() +
" comment(s). Click here to view.");
}
}
11
Exemplo – Rede Social
12
Exemplo – Rede Social
public class PhotoPost {
private String username; Nome do ficheiro com a imagem
private String filename;
private String caption;
private long timestamp;
Legenda da imagem
private int likes;
private ArrayList<String> comments;
// continua…
13
Exemplo – Rede Social
public void like() { ▸ Métodos da classe
likes++;
} PhotoPost (1/3)
public void unlike() {
if (likes > 0) {
likes--;
}
}
public void addComment(String text) {
comments.add(text);
}
public String getImageFile() {
return filename;
}
public String getCaption() {
return caption;
}
14
Exemplo – Rede Social
public long getTimeStamp() {
return timestamp;
▸ Métodos da classe
}
public void display() {
PhotoPost (2/3)
System.out.println(username);
System.out.println(" [" + filename + "]");
System.out.println(" " + caption);
System.out.print(timeString(timestamp));
if(likes > 0) {
System.out.println(" - " + likes + " people like this.");
}
else {
System.out.println();
}
if(comments.isEmpty()) {
System.out.println(" No comments.");
}
else {
System.out.println(" " + comments.size() + " comment(s). Click here to view.");
}
}
15
Exemplo – Rede Social
16
Exemplo – Rede Social
public class NewsFeed {
private ArrayList<MessagePost> messages; ▸ Classe NewsFeed
private ArrayList<PhotoPost> photos;
public NewsFeed() {
messages = new ArrayList<MessagePost>();
photos = new ArrayList<PhotoPost>();
}
// continua…
17
Exemplo – Rede Social
// continuação da classe Newsfeed… ▸ Classe NewsFeed
public void show() {
// display all text posts
for(MessagePost message : messages) {
message.display();
System.out.println(); // empty line between posts
}
18
Exemplo – Rede Social
▸ Problemas do protótipo criado:
▹ Duplicação de código
Atributos
Métodos
21
Exemplo – Rede Social
▸ Solução: Herança de classes Constroi-se uma
nova classe (Post)
com o código
comum.
22
Herança de classes
Herança de classes
▸ É uma técnica usada em Programação Orientada por Objetos que vai permitir a reutilização de código.
▹ Define-se uma classe com o código comum.
▹ Criam-se outras classes com base na classe anterior que reutilizam esse código.
▹ A classe criada inicialmente é a superclasse e as classes que vão reutilizar essa classe são as subclasses.
23
Exemplo – Rede Social
▸ Solução: usar a Herança de classes
25
Exemplo – Rede Social
26
Exemplo – Rede Social
public class MessagePost extends Post {
private String message; ▸ Subclasses –
27
Exemplo – Rede Social
▸ Herança de classes em Java
Atributos
idênticos
28
Exemplo – Rede Social
▸ Herança de classes em Java
Métodos
idênticos
Mesma
utilização
30
Herança de classes
▸ Herança de classes
32
Herança – Hierarquia de Classes - vocabulário
Animal é superclasse
direta (classe base ou
classe pai) de Mammal e
Bird, e é super classe
Animal
indireta de Dog, Cat e Cow
Mammal é subclasse
direta (classe derivada ou
classe filha) de Animal e
super classe direta (base
Mammal Bird
ou pai) de Dog, Cat e Cow
33
Herança
▸ As subclasses ou classes derivadas vão herdar todos os atributos e métodos da superclasse ou classe
base.
▸ As subclasses não herdam os construtores da superclasse
34
Construtores em Herança
▸ Herança de Classes
Herança
▸ As subclasses não herdam os construtores da superclasse
public class Post {
private String username;
private long timestamp;
private int likes;
private ArrayList<String> comments;
37
Exemplo – Rede Social
public class Post {
private String username; ▸ Construtores em herança –
private long timestamp;
private int likes; classe Post
private ArrayList<String> comments;
// métodos omitidos
}
38
Exemplo – Rede Social
▸ Construtores em herança
public class MessagePost extends Post {
private String message; – classe MessagePost
public MessagePost(String author, String text) {
super(author);
message = text;
} Chamada ao
construtor da
// métodos omitidos superclasse (Post)
}
39
Construtores em herança
▸ Construtores em herança
▹ O construtor da subclasse deve incluir sempre uma chamada ao construtor da superclasse
▹ Se não for incluída o compilador coloca automaticamente uma chamada ao construtor sem
argumentos da superclasse: super();
▹ Apenas resulta se a superclasse tiver um construtor sem argumentos
// métodos omitidos
Primeira instrução do construtor
}
40
Herança
public class Post {
private String username;
▸ As subclasses não herdam
private long timestamp;
private int likes;
os construtores da
private ArrayList<String> comments;
superclasse
public Post(String author) {
username = author;
timestamp = System.currentTimeMillis();
likes = 0;
comments = new ArrayList<String>();
}
}
}
41
Herança por Extensão
▸ Herança de Classes
Modificadores de acesso do Java
▸ Membros public (símbolo + nos diagramas de classe): Se os membros são declarados como públicos
dentro de uma classe, então estes membros são acessíveis às classes que estão dentro e fora do
pacote onde esta classe é visível. Este é o menos restritivo de todos os modificadores de
acessibilidade.
▸ Membros protected (símbolo # nos diagramas de classe) : se os membros de uma classe são
declarados como protegidos, eles estarão acessíveis a todas as classes do pacote e a todas as
subclasses desta classe em qualquer pacote em que essa classe esteja visível.
▸ Membros default (nenhum símbolo) : quando nenhum modificador de acessibilidade é especificado para
o membro, ele é implicitamente declarado como visibilidade por defeito. Eles são acessíveis apenas
para as outras classes no pacote da classe.
▸ Membros private (símbolo - nos diagramas de classe) : Este é o mais restritivo de todos os
modificadores de acessibilidade. Esses membros são acessíveis apenas dentro desta classe. Eles não
são acessíveis a partir de nenhuma outra classe dentro do pacote da classe.
43
Exemplo – Rede Social
▸ Adição de outro tipo de Posts – EventPost
*métodos omitidos
Nova classe
EventPost.
44
Exemplo – Rede Social
▸ Hierarquias mais complexas
*métodos omitidos
45
Exemplo – Rede Social
• Simplifica a manutenção
46
Principio da substituição
▸ Herança de Classes
Principio da Substituição
Subclasses e Subtipos
▸ Uma classe define um tipo
▸ Uma subclasse define um subtipo
▸ Sempre que é necessário um objeto de uma classe, pode-se usar em vez disso um objeto
de uma subclasse:
▹ Chama-se principio da substituição
▹ Exemplo
Post post = new MessagePost("João", "Olá Mundo");
49
Principio da Substituição
public class NewsFeed {
▸ Principio da substituição
public void addPost(Post post) aplicado à passagem de
{
... parâmetros
}
}
feed.addPost(photo);
Objetos de subclasses
feed.addPost(message);
podem ser usados como
parâmetros atuais para
superclasses
50
Exemplo – Rede Social
public class NewsFeed {
private ArrayList<Post> posts;
▸ Nova classe NewsFeed
public NewsFeed() {
posts = new ArrayList<Post>();
}
51
Exemplo – Rede Social
▸ Diagrama de objetos
52
Exemplo – Rede Social
▸ Diagrama de classes
53
Exemplo – Rede Social
▸ Antiga classe versus nova classe NewsFeed
public class NewsFeed { public class NewsFeed {
private ArrayList<MessagePost> messages; private ArrayList<Post> posts;
private ArrayList<PhotoPost> photos;
public NewsFeed() {
public NewsFeed() {
messages = new ArrayList<MessagePost>();
posts = new ArrayList<Post>();
photos = new ArrayList<PhotoPost>();
} }
public void addMessagePost(MessagePost message) {
messages.add(message); public void addPost(Post post) {
} posts.add(post);
public void addPhotoPost(PhotoPost photo) { }
photos.add(photo);
}
public void show() {
public void show() {
for(Post post : posts) {
for(MessagePost message : messages) {
message.display(); post.display();
System.out.println(); System.out.println();
} }
for(PhotoPost photo : photos) { }
photo.display(); }
System.out.println();
}
}
}
54
Bibliografia
55
Programação Orientada por Objetos
Herança de
classes -
exemplo
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Redefinição de métodos
▸ A Classe Object
2
Exemplo – Xadrez
▸ Requisitos do protótipo:
▹ Representar os componentes do jogo sem
implementar as regras ou o desenrolar do jogo.
▹ Representar as peças: peão, torre, cavalo, rei,
rainha e bispo.
▹ Representar o tabuleiro de jogo com as posições.
▹ Deve ser possível obter em texto a posição de
cada peça usando a notação algébrica (ex: e5 –
peão na casa e5, ou Te7 – torre na casa e7).
3
Exemplo – Xadrez
Representação 1
▹ Cada peça poderá ser representada
por uma classe
▹ Peças: peão, torre, cavalo, rei, rainha
e bispo.
▹ O tabuleiro de jogo corresponde a
outra classe.
4
Exemplo – Xadrez
Representação 1
▹ Cada peça poderá ser
representada por uma classe
▹ Peças: peão, torre, cavalo, rei,
rainha e bispo.
▹ O tabuleiro de jogo
corresponde a outra classe.
5
Exemplo – Xadrez
▸ Representação 1 – Classes Pawn e Rook
public class Pawn { public class Rook {
public Pawn(Colour colour, Position position) { public Rook(Colour colour, Position position) {
this.colour = colour; this.colour = colour;
if (position != null) { if (position != null) {
this.position = position; this.position = position;
} else { } else {
this.position = new Position(); this.position = new Position();
} }
} }
7
Exemplo – Xadrez
8
Exemplo – Xadrez
Representação 2
▹ Criar uma classe peça que
representa qualquer peça
▹ Usar um atributo PieceType que
determina qual a peça
representada.
▹ O tabuleiro de jogo corresponde a
outra classe.
9
Exemplo – Xadrez
▸ Representação 2 – Classe Piece
public class Piece { public String toString() {
String text = "";
private Colour colour; switch(pieceType){
private Position position; case ROOK:
private PieceType pieceType; text += 'T';
break;
public Piece(PieceType pieceType, case KNIGHT:
Colour colour, Position position) { text += 'C';
this.pieceType = pieceType; break;
this.colour = colour;
case BISHOP:
if (position != null) {
text += 'B';
this.position = position;
} else { break;
this.position = new Position(); case QUEEN:
} text += 'D';
} break;
case KING:
public Colour getColour() { ... } text += 'R';
public PieceType getPieceType() { ... } break;
public void setPieceType(PieceType pieceType) { ... } }
public Position getPosition() { ... } text += position.toString();
public void setPosition(char x, int y) { ... } return text;
public void setPosition(Position position) { ... } }
public void setY(int y) { ... }
public char getX() { ... }
public int getY() { ... } public String getName() { ... }
}
}
10
Exemplo – Xadrez
▸ Representação 2 – private void setup() {
Classe ChessBoard
for (char x = 'a'; x <= 'h'; x++) {
pieces.add(new Piece(PieceType.PAWN, Colour.WHITE, new Position(x, 2)));
pieces.add(new Piece(PieceType.PAWN, Colour.BLACK, new Position(x, 7)));
}
int line = 1;
Colour colour = Colour.WHITE;
pieces.add(new Piece(PieceType.ROOK, colour, new Position('a', line)));
pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('b', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('c', line)));
pieces.add(new Piece(PieceType.QUEEN, colour, new Position('d', line)));
public class Chessboard { pieces.add(new Piece(PieceType.KING, colour, new Position('e', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('f', line)));
ArrayList<Piece> pieces; pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('g', line)));
pieces.add(new Piece(PieceType.ROOK, colour, new Position('h', line)));
public Chessboard() { line = 8;
pieces = new ArrayList<>(); colour = Colour.BLACK;
setup(); pieces.add(new Piece(PieceType.ROOK, colour, new Position('a', line)));
} pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('b', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('c', line)));
pieces.add(new Piece(PieceType.QUEEN, colour, new Position('d', line)));
pieces.add(new Piece(PieceType.KING, colour, new Position('e', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('f', line)));
pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('g', line)));
pieces.add(new Piece(PieceType.ROOK, colour, new Position('h', line)));
}
}
11
Exemplo – Xadrez
12
Exemplo – Xadrez
▸ Solução:
13
Exemplo – Xadrez
▸ Requisitos do protótipo:
▹ Representar os componentes do jogo sem
implementar as regras ou o desenrolar do jogo.
▹ Representar as peças: peão, torre, cavalo, rei,
rainha e bispo.
▹ Representar o tabuleiro de jogo com as
posições.
▹ Deve ser possível obter em texto a posição de
cada peça usando a notação algébrica (ex: e5 –
peão na casa e5, ou Te7 – torre na casa e7). 14
Exemplo – Xadrez (3)
▸ Representação 3 – Usar a herança:
▹ Definir cada uma das peças como uma subclasse da classe Piece
16
Exemplo – Xadrez (3)
▸ Exemplo de objetos da representação 1
Atributos
idênticos
Métodos
idênticos
17
Exemplo – Xadrez (3)
public class Piece {
19
Exemplo – Xadrez (3)
public void setY(int y) {
position.setY(y);
}
▸ Classe Piece – métodos (2/2)
public char getX() {
return position.getX();
}
20
Exemplo – Xadrez (3)
▸ Classe Rook
21
Classes Pawn e Rook
27
Exemplo – Xadrez (3)
▸ Classes Queen, King, Bishop, Knight
▹ Omitidas: são semelhantes às anteriores public class Chessboard {
▸ Classe Chessboard
ArrayList<Piece> pieces;
public Chessboard() {
pieces = new ArrayList<>();
setup();
Apenas uma lista para }
guardar as várias peças
// métodos omitidos
}
28
private void setup() {
Exemplo –
for (char x = 'a'; x <= 'h'; x++) {
pieces.add(new Pawn(Colour.WHITE, new Position(x, 2)));
pieces.add(new Pawn(Colour.BLACK, new Position(x, 7)));
}
int line = 1;
Xadrez (3)
Colour colour = Colour.WHITE;
pieces.add(new Rook(colour, new Position('a', line)));
pieces.add(new Knight(colour, new Position('b', line)));
pieces.add(new Bishop(colour, new Position('c', line)));
pieces.add(new Queen(colour, new Position('d', line)));
pieces.add(new King(colour, new Position('e', line)));
pieces.add(new Bishop(colour, new Position('f', line)));
pieces.add(new Knight(colour, new Position('g', line)));
pieces.add(new Rook(colour, new Position('h', line)));
▸ Classe Chessboard –
line = 8;
método setup colour = Colour.BLACK;
pieces.add(new Rook(colour, new Position('a', line)));
pieces.add(new Knight(colour, new Position('b', line)));
pieces.add(new Bishop(colour, new Position('c', line)));
pieces.add(new Queen(colour, new Position('d', line)));
A inicialização tem pieces.add(new King(colour, new Position('e', line)));
de ser feita com o pieces.add(new Bishop(colour, new Position('f', line)));
pieces.add(new Knight(colour, new Position('g', line)));
mesmo detalhe pieces.add(new Rook(colour, new Position('h', line)));
}
29
Exemplo – Formas Geométricas
Requisitos do programa:
30
Exemplo – Formas Geométricas
radius side
x,y
x,y
Circle Square
31
Exemplo – Formas Geométricas
32
Exemplo – Formas Geométricas
public class Circle { public int getX() {
private int x, y;
return x;
private int radius;
}
public Circle() {
public void setX(int x) {
this.x = 0;
this.x = x;
this.y = 0;
this. radius = 1; }
} public int getY() {
public Circle(int x, int y, int radius) { return y;
this.x = x;
}
this.y = y;
public void setY(int y) {
this. radius = radius;
this.y = y;
}
}
public int getRadius() {
return radius; public void move( int dx, int dy ) {
} x += dx; y += dy;
public void setRadius(int raio) { }
this. radius = radius; }
}
33
Exemplo – Formas Geométricas
public class Square { public int getX() {
private int x, y;
return x;
private int side;
}
public Square() {
this.x = 0; public void setX(int x) {
this.y = 0; this.x = x;
this.side = 1; }
}
public int getY() {
public Square(int x, int y, int side) {
return y;
this.x = x;
this.y = y; }
this.side = side; public void setY(int y) {
}
this.y = y;
public int getSide() {
}
return side;
} public void move( int dx, int dy ) {
public void setSide(int side) { x += dx; y += dy;
this.side = side; }
}
}
34
public class Program {
public static void main(String[] args) {
Circle circle = new Circle(1, 1, 23);
35
Exemplo – Formas Geométricas
▸ As classes Circle e Square têm em comum alguns dos atributos e métodos
(código duplicado):
▹ 2 atributos (x e y)
36
Exemplo – Formas Geométricas
37
Exemplo – Formas Geométricas
public int getX() {
41
Exemplo – Formas Geométricas
42
Exemplo – Formas Geométricas
Acrescenta os atributos x2 e y2 para a
representação do segundo ponto do
segmento de retas
public class LineSegment extends GeometricShape {
public int getX2() {
private int x2, y2;
return x2;
public LineSegment() {
}
super(0, 0);
public void setX2(int x2) {
this.x2 = 1;
this.x2 = x2;
this.y2 = 1;
}
}
public int getY2() {
public LineSegment(int x, int y, int x2, int y2) {
return y2;
super(x, y);
}
this.x2 = x2;
Existe um método que public void setY2(int y2) {
this.y2 = y2; é herdado mas não é
this.y2 = y2;
} adequado nesta classe.
Qual? }
}
43
Herança – Redefinição de Métodos
▸ O método:
public void move( int dx, int dy ) {
x += dx; y += dy;
}
▹ Este método não funciona corretamente para objetos da classe LineSegment.
▹ A solução é redefinir este método nesta classe.
▹ Para redefinir um método basta defini-lo novamente no corpo da subclasse:
@Override
public void move( int dx, int dy ) {
super.move(dx, dy);
x2 += dx; y2 += dy;
}
}
44
Exemplo – Formas Geométricas
45
Considerações Finais
▸ Herança de classes
46
Herança (is-a) – Generalização vs Especialização
Versus …
47
Herança (is-a) – Generalização vs Especialização
▸ Na prática a herança utiliza-se por generalização e por especialização de classes
48
Herança (is-a) – Generalização vs Especialização
o
lizaçã
a
ner
Ge
49
Herança (is-a) – Generalização vs Especialização
Es
pe
cia
liz
aç
ão
50
Classe Object
▸ A classe Object é uma classe do Java, que está no topo da hierarquia e da
qual todas as outras são subclasses diretas ou indiretas.
▹ Todas as classes são uma especialização de Object, são todas um
tipo de objeto.
▹ Quando uma classe não deriva de outra o compilador de Java coloca-
a a derivar de Object (é acrescentado extends Object).
▹ A classe Object define um conjunto de métodos que são herdados
por todas as classes, entre eles estão os métodos: toString, equals
e hashCode utilizados antes.
▹ Por isso quando se coloca um destes métodos numa classe, na
prática está-se a redefinir o método herdado, sendo então
necessário colocar @Override antes da redefinição
51
Exemplo – Xadrez (3)
▸ Classe Object
52
Bibliografia
53
Programação Orientada por Objetos
Polimorfismo
▸ Principio da Substituição
▸ Tipos Estáticos e Tipos Dinâmicos
▸ Polimorfismo
▸ Exemplo Formas Geométricas
2
Principio da Substituição
▸ Polimorfismo
3
Exemplo – Rede Social
4
Exemplo – Rede Social
▸ Solução com herança de classes:
Classe base Post
com o código
comum
Classes derivadas
MessagePost e
PhotoPost
5
Exemplo – Rede Social
▸ Exemplo de utilização
O texto da
mensagem não é
mostrado
6
Exemplo – Rede Social
▸ Exemplo de utilização
7
Exemplo – Rede Social
▸ Exemplo de utilização
public class Post {
private String username;
private long timestamp;
private int likes;
A informação mostrada está
private ArrayList<String> comments; incompleta para as classes
MessagePost e
// restante código omitido PhotoPost
public void display() {
System.out.println(username);
System.out.print(timeString(timestamp));
if(likes > 0) {
System.out.println(" - " + likes + " people like this.");
}
else {
System.out.println();
} Solução:
if(comments.isEmpty()) { Redefinir o método nas
System.out.println(" No comments."); classes derivadas
}
else {
System.out.println(" " + comments.size() +
" comment(s). Click here to view.");
}
}
} 8
Exemplo – Rede Social
public class MessagePost extends Post {
private String message;
▸ Exemplo de utilização
// restantes métodos omitidos
@Override
public void display() {
super.display();
System.out.println(message);
}
}
Acrescenta o texto da
mensagem no caso de
objetos MessagePost
10
Principio da Substituição
▸ Subclasses e Subtipos
▸ Uma classe define um tipo
▸ Uma subclasse define um subtipo
▸ Sempre que é necessário um objeto de uma classe pode-se usar em vez disso um
objeto duma subclasse:
▹ Chama-se principio da substituição
▹ Exemplo
Post post = new MessagePost("João", "Olá Mundo");
display de
MessagePost
display de PhotoPost
12
Principio da Substituição
▸ Exemplo de utilização
13
Principio da Substituição
▸ Exemplo de utilização
14
Tipos Estáticos e
Dinâmicos
▸ Polimorfismo
15
Exemplo – Rede Social
16
Exemplo – Rede Social
▸ Classe MessagePost
// métodos omitidos
O método requerido
public String getText() { já existia na classe
return message; MessagePost
}
}
17
Exemplo – Rede Social
▸ Classe PhotoPost
}
18
Exemplo – Rede Social
▸ Superclasse – Post
19
Principio da Substituição
▸ Exemplo de utilização – método getText
Erro???
20
Tipos Estáticos e Tipos dinâmicos
21
Tipos Estáticos e Tipos dinâmicos
▸ O tipo declarado de uma variável é o seu tipo estático (static type)
▸ O tipo do objeto referido pela variável é o seu tipo dinâmico (dynamic type)
▸ O compilador verifica sempre se existem erros nos tipos estáticos.
▹ Não é possível referir objetos que não sejam da classe do tipo estático ou de uma das classes
derivadas do mesmo.
▹ Não é possível chamar métodos para uma variável que não existam no seu tipo estático. Ou seja, que
não existam na classe declarada.
22
Tipos Estáticos e Tipos dinâmicos
23
Tipos Estáticos e Tipos dinâmicos
No caso do método
display não há
problema porque existe
na classe base e nas
classes derivadas
Satisfaz a verificação
estática (e dinâmica)
do tipo
24
Tipos Estáticos e Tipos dinâmicos
O método getText
só existe nas
classes derivadas
Não satisfaz a
verificação estática
do tipo
25
Tipos Estáticos e Tipos dinâmicos
26
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime)
27
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime) – procura do método a executar:
O método display a
executar apenas pode
ser o que está em Neste exemplo não
PhotoPost existe herança
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime) – procura do método a executar:
31
Polimorfismo
▸ Polimorfismo
32
Polimorfismo
▸ Quando executamos um método, o método que é executado depende da classe do objeto que o
executa. Neste caso dizemos que temos polimorfismo de métodos.
▹ Um método várias (poli) formas (Morfo) de resposta
▹ O método display tem várias formas de resposta, dentro da classe MessagePost tem uma
forma, dentro da classe PhotoPost tem outra forma.
▹ O método que realmente é chamado depende do tipo do objeto em tempo de execução (o tipo dinâmico)
33
Polimorfismo
▸ Para solucionar este erro ter-se-ia que criar o método getText na classe
Post mesmo que não fizesse nada
public class Post {
▸ Na execução, o método getText executado vai corresponder ao método getText da classe do objeto
public class PhotoPost extends Post {
public class MessagePost extends Post { private String filename;
private String message; private String caption;
// código omitido // código omitido
@Override @Override
public String getText() { public String getText() {
return message; return caption;
} }
} }
35
Polimorfismo
▸ Poliformismo
36
▸ Polimorfismo
Exemplo Formas
geométricas
37
Exemplo – Formas Geométricas
▸ Requisitos do programa:
▹ Desenho de formas geométricas.
▹ Representar círculos, quadrados e retângulos.
▹ Deve ser possível saber as dimensões e a posição de cada um deles.
▹ Deve ser possível deslocá-los.
38
Polimorfismo - exemplo
▸ Exemplo de formas geométricas
raio radiu x,
s y
x,y
x,y
x,y
lad
x2,y o
2
Círculo Retângulo Quadrado
39
Polimorfismo - exemplo
40
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
42
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
public class Shape { public circle() { this.radius = 1; }
private int x, y; public circle(int x, int y, int radius) {
super(x, y); this.radius = radius; }
public Shape () { public int getRadius() { return radius; }
x = 0; public void setRadius(int radius) { this.radius = radius; }
y = 0; }
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; public Rectangle() {this.x2 = 0; this.y2 = 0; }
this.y = y; public Rectangle(int x, int y, int x2, int y2) {
formas geométricas!!!
public void setY2(int y2) { this.y2 = y2; }
}
}
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
private int side;
} public Square() {this.side = 1;}
public int getY() { public Square(int x, int y, int side) {
return y; super(x, y, x+side, y+side); this.side = side;}
public int getSide() {return side;}
}
public void setSide(int side) { this.side = side;
public void setY(int y) {
setX2(getX() + side);setY2(getY() - side); }
this.y = y; @Override public void setX(int x) { super.setX(x);
} setX2(getX() + side); } ... }
} 43
Polimorfismo - exemplo
public class Shape {
public class circle extends Shape {
private int radius;
@Override
private int x, y;
public double getArea() {
return Math.PI*radius*radius;
public Shape () {
getArea do
}
círculo
x = 0;
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; public Rectangle() {this.x2 = 0; this.y2 = 0; }
this.y = y; public Rectangle(int x, int y, int x2, int y2) {
super(x, y); this.x2 = x2;this.y2 = y2; }
}
public int getX2() { return x2; }
public int getX() { public void setX2(int x2) { this.x2 = x2; }
return x; public int getY2() { return y2; }
public void setY2(int y2) { this.y2 = y2; }
}
}
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
private int side;
} public Square() {this.side = 1;}
public int getY() { public Square(int x, int y, int side) {
return y; super(x, y, x+side, y+side); this.side = side;}
public int getSide() {return side;}
}
public void setSide(int side) { this.side = side;
public void setY(int y) {
setX2(getX() + side);setY2(getY() - side); }
this.y = y; @Override public void setX(int x) { super.setX(x);
} setX2(getX() + side); } ... }
} 44
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
public class Shape {
@Override
private int x, y;
public double getArea() {
return Math.PI*radius*radius;
public Shape () {
x = 0; }
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; @Override
this.y = y; public double getArea() {
} double dx = x2 - getX();
return Math.PI*radius*radius;
public Shape () {
x = 0; }
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; @Override
this.y = y; public double getArea() {
} double dx = x2 - getX();
double dy = y2 - getY();
public int getX() {
return Math.abs(dx * dy);
return x; }
} } // Restante código omitido
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
getArea do quadrado private int side;
não é necessária, o
}
public int getY() {
return y;
método herdado serve
} // Restante código omitido
}
public void setY(int y) {
this.y = y;
}
} 46
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
@Override
public class Shape {
public double getArea() {
private int x, y;
return Math.PI*radius*radius;
}
public Shape () {
x = 0; } // Restante código omitido
y = 0;
public class Rectangle extends Shape {
}
private int x2, y2;
public Shape (int x, int y) {
return y;
} } // Restante código omitido
this.y = y;
}
} 47
public class circle extends Shape {
private int radius;
polimorfismo funcionar.
private int side;
return 0.0;
}
} 48
Polimorfismo - exemplo
Usamos o principio da
public class Main{ substituição para guardar
public static void main(String[] args) { as diferentes formas
Shape[] shapes; geométricas no mesmo
shapes = new Shape[6]; array
shapes[0] = new circle(4, 8, 3);
shapes[1] = new circle(28, 10, 4);
shapes[2] = new Rectangle(3, 0, 5, 6);
shapes[3] = new Rectangle(11, 0, 23, 6);
shapes[4] = new Rectangle(18, 0, 21, 4); Calculamos a área
shapes[5] = new Square(13, 2, 2); aplicando o
double totalArea = 0; polimorfismo. Cada
forma geométrica
for (int i=0; i < shapes.length; i++) { retorna a sua área
totalArea += shapes[i].getArea();
}
System.out.println("Area Total: " + totalArea);
}
}
49
Polimorfismo - exemplo
public class Main{
public static void main(String[] args) {
ArrayList<Shape> shapes = new ArrayList<>();
shapes.add(new circle(4, 8, 3));
shapes.add(new circle(28, 10, 4));
shapes.add(new Rectangle(3, 0, 5, 6));
Alternativa
shapes.add(new Rectangle(11, 0, 23, 6)); com listas!
shapes.add(new Rectangle(18, 0, 21, 4));
shapes.add(new Square(13, 2, 2));
double totalArea = 0;
50
Bibliografia
51
Programação Orientada por Objetos
Polimorfismo
- Exemplo
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Organização de Código
2
Desenho Casa –
Solução 1
▸ Polimorfismo
3
Exemplo – Desenho Casa
▸ Requisitos do desenho (Revisitado):
▹ O desenho é composto por quadrados, triângulos, círculos e
retângulos.
▹ Cada uma das formas geométricas tem uma cor e uma
posição.
▹ O desenho reutiliza as classes Pen e Canvas do ambiente
gráfico. Neste caso as figuras são desenhadas apenas com as
linhas de contorno.
▹ Deverá ser possível criar facilmente outros desenhos com as
figuras geométricas existentes (circulo, quadrado, triângulo e
retângulo).
4
Exemplo – Desenho Casa
Foram criadas 2 soluções:
▸ Solução 1:
Circle, Triangle.
▹ Uma classe Figure que pode ser qualquer das figuras existentes.
▹ Uma classe Drawing para o desenho que guarda uma lista de figuras.
5
Exemplo – Desenho casa
▸ Classe Position para representar a posição das figuras:
public class Position { public int getX() {
return x;
private int x; }
private int y;
public int getY() {
public Position() { return y;
x = 0; }
y = 0;
} public void setX(int x) {
this.x = x;
public Position(int x, int y) { }
this.x = x;
this.y = y; public void setY(int y) {
} this.y = y;
}
// continua ao lado... }
6
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▹ Classe Square
public class Square { É necessária uma pen
externa para desenhar o
private Pen pen; quadrado na superfície
private Color color; associada
private Position position;
private int side;
// restante código
public void draw() {
pen.setColor(color);
pen.penUp();
pen.moveTo(position.getX(),position.getY());
pen.penDown();
Através dos pen.turnTo(0);
movimentos da pen
é possível efetuar o for(int i=0; i<4; i++) {
desenho duma figura pen.move(side);
pen.turn(90);
}
}
}
8
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▸ Classe Circle public class Circle {
private Pen pen;
private Color color;
private Position position;
private int radius;
Vários atributos
em comum com
a classe Square public Circle(Pen pen,Color color,Position position, int radius) {
this.pen = pen;
this.color = color;
this.position = position;
this.radius = radius;
}
// restante código
}
9
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▹ Classe Circle
public class Circle {
// restante código
public void draw() {
pen.setColor(color);
pen.penUp();
pen.moveTo(position.getX(),position.getY());
Estamos a
pen.penDown();
criar círculos pen.turnTo(0);
aproximados
int sides = 50;
por polígonos
int side = (int)(2*Math.PI*radius/sides);
regulares de
for(int i=0; i<sides+1; i++) {
50 lados.
pen.move(side);
pen.turn((int)(360.0/sides));
}
}
}
10
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▹ Classe Triangle public class Triangle {
private Pen pen;
private Color color;
private Position position
private int height, width;
Com atributos
// restante código
em comum com
void draw() {
as outras classes pen.penUp();
pen.moveTo(x, y);
pen.penDown();
pen.turnTo(0);
13
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
▹ Tipo FigureType
14
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
▹ Classe Figure - Construtores
public Figure(FigureType figureType, Pen pen, Color color,
Position position, int dimension) {
this.figureType = figureType;
if (figureType == FigureType.CIRCLE) {
circle = new circle(pen, color, position, dimension);
} else { Confuso!
square = new Square(pen, color, position, dimension);
}
}
public Figure(FigureType figureType, Pen pen, Color color,
Position position, int height, int width) {
this.figureType = figureType;
if (figureType == FigureType.TRIANGLE) {
triangle = new Triangulo(pen, color, position, height, width);
} else {
rectangle = new Retangulo(pen, color, position, height, width);
}
}
15
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
▹ Classe Figure - draw public void draw() {
switch(figureType) {
case CIRCLE:
Um switch para lidar circle.draw();
com os diferentes tipos break;
case TRIANGLE:
de figura
triangle.draw();
break;
case RECTANGLE:
rectangle.draw();
break;
Muitas vezes as instruções switch são pistas que
nos indicam que poderá existir um problema de case SQUARE:
coesão onde estão representadas várias square.draw();
entidades e em que a solução passa pela break;
herança (e polimorfismo)
}
}
16
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
public class Drawing {
▹ Classe Drawing private ArrayList<Figure> figures;
public Drawing() {
figures = new ArrayList<>();
}
drawing.addFigure(wall);
drawing.addFigure(window);
drawing.addFigure(roof);
drawing.addFigure(sun);
drawing.draw();
}
}
19
Exemplo – Desenho casa
20
Desenho Casa –
Solução 2
▸ Polimorfismo
21
Exemplo – Desenho Casa
▸ Requisitos do desenho (Revisitado):
▹ O desenho é composto por quadrados, triângulos, círculos e
retângulos.
▹ Cada uma das formas geométricas tem uma cor e uma
posição.
▹ O desenho reutiliza as classes Pen e Canvas do ambiente
gráfico. Neste caso as figuras são desenhadas apenas com
as linhas de contorno.
▹ Deverá ser possível criar facilmente outros desenhos com as
figuras geométricas existentes (circulo, quadrado, triângulo
e retângulo).
22
Exemplo – Desenho Casa
▸ Foram criadas 2 soluções:
▹ Solução 1:
▹ Classes para cada tipo de forma geométrica: Square, Rectangle,
Circle, Triangle.
▹ Um classe Figure que pode ser qualquer das figuras existentes.
▹ Uma classe Drawing para o desenho que guarda uma lista de figuras.
▹ Solução 2:
▹ Uma classe Figure que representa qualquer figura.
▹ Uma classe Drawing para o desenho que guarda uma lista de figuras.
23
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure
public class Figure { Tipo enumerado TipoFigura para
definir o tipo de figura guardado
private FigureType type;
private Pen pen;
private Position position;
private Color color;
private int height; Atributos
private int width;
necessários para
private int radius;
os vários tipos de
figura que poderão
// restante código
}
ser utilizados
24
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Tipo FigureType
25
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - Construtor
26
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - setCircle e setSquare
pen.penUp();
pen.moveTo(position.getX(), position.getY());
pen.setColor(color);
pen.penDown();
// continua…
29
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - draw
switch (type) {
case CIRCLE:
drawCircle();
break;
case TRIANGLE:
drawTriangle();
break;
case RECTANGLE:
drawRectangle();
break;
case SQUARE:
drawSquare();
break;
}
}
30
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - drawSquare e drawCircle
private void drawSquare() {
for (int i = 0; i < 4; i++) {
pen.move(width);
pen.turn(90);
}
}
private void drawCircle() {
int sides = 50;
int side = (int) (2 * Math.PI * radius / sides);
32
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - drawTriangle
33
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Drawing public class Drawing {
private ArrayList<Figure> figures;
public Drawing() {
figures = new ArrayList<>();
}
35
Exemplo – Desenho casa
▸ Solução 2 – Programa principal
▹ Ex: representar o desenho da casa
drawing.draw();
}
36
Exemplo – Desenho casa
37
Desenho Casa:
Herança e Polimorfismo
▸ Polimorfismo
38
Exemplo – Desenho Casa
▸ Problemas das soluções apresentadas:
▹ Solução 1
▹ Código duplicado nas várias formas geométricas
▹ Classe Figure com um atributo por cada tipo de forma geométrica
▹ Solução 2
▹ Classe Figure complexa
▹ Classe Figure com problemas de coesão ao representar as várias
formas geométricas
39
Exemplo – Desenho Casa
▸ Solução com herança de classes e polimorfismo:
▹ Criar uma superclasse Figure com os atributos comuns das formas
geométricas
▹ Criar sublasses para cada uma das formas geométricas.
▹ Criar uma classe Drawing que irá guardar uma lista de formas
geométricas tirando partido do Principio da Substituição
▹ Método draw da classe Figure polimórfico.
▹ O resultado da sua execução depende da figura que estiver na lista.
40
Exemplo – Desenho Casa
▸ Classes da solução 1: public class Rectangle {
public class Square {
private Pen pen;
private Pen pen; private Color color;
private Color color; private Position position;
private Position position; private int height, width;
private int side;
// restante código
// restante código Vários atributos
em comum }
}
Construtor sem
public Figure() {
argumentos
pen = new Pen();
position = new Position();
color = Color.BLACK;
}
// restante código
}
42
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure(Position position,
public Figure() {
Pen pen, Color color) {
pen = new Pen();
if (pen != null) {
position = new Position();
this.pen = pen;
color = Color.BLACK;
} else {
}
this.pen = new Pen();
}
public Figure(Pen pen, Color color) {
if (position != null) {
if (pen != null) {
this.position =
this.pen = pen;
new Position(position.getX(),
} else {
position.getY());
this.pen = new Pen();
} else {
}
this.position = new Position();
position = new Position();
}
if (color != null) {
if (color != null) {
this.color = color;
this.color = color;
} else {
this.color = Color.BLACK; Aqui também existe } else {
this.color = Color.BLACK;
} alguma duplicação
}
} de código }
43
Construtores – this()
public class Clock {
▸ this() nos construtores
private int hours;
▹ Da mesma maneira que se utiliza private int minutes;
private int seconds;
super() para a chamada ao Chamada ao construtor:
public Clock(){ Clock(int hours, int
construtor da classe base é this(0,0,0); minutes, int seconds)
}
possível usar this() para a
public Clock(int hours, int minutes){
chamada doutro construtor da this(hours, minutes, 0);
própria classe. }
44
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure(Position position,
Pen pen, Color color) {
if (pen != null) {
this.pen = pen;
public Figure() { } else {
this(new Position(), new Pen(), Color.BLACK); this.pen = new Pen();
} }
if (position != null) {
this.position =
public Figure(Pen pen, Color color) {
new Position(position.getX(),
this(new Position(), pen, color); position.getY());
} } else {
this. position = new Position();
}
if (color != null) {
this.color = color;
Assim evita-se a } else {
duplicação de código nos
this.color = Color.BLACK;
construtores }
} 45
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure(Position position,
Pen pen, Color color) {
public Figure() { if (pen != null) {
this(new Position(), new Pen(), Color.BLACK); this.pen = pen;
} } else {
this.pen = new Pen();
}
public Figure(Pen pen, Color color) {
if (position != null) {
this(new Position(), pen, color); this.position =
} new Position(position.getX(),
position.getY());
} else {
this. position = new Position();
}
Outra simplificação que
if (color != null) {
pode ser feita é a utilização this.color = color;
do operador ternário em } else {
substituição dos if this.color = Color.BLACK;
}
} 46
Operador ternário
▸ Operador ternário – ?!
String period;
if (hours < 12) {
Ø Equivalente com ifs: period = "am";
} else {
period = "pm";
}
47
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure() {
this(new Position(), new Pen(), Color.BLACK);
}
48
Exemplo – Desenho Casa
▸ Solução 3 – classe derivada Circle
public class Circle extends Figure {
public Circle() {
this.radius = 1;
}
// restante código
} 49
Exemplo – Desenho Casa
@Override
▸ Solução 3 – classe public void draw() {
derivada Circle: Pen pen = getPen();
pen.setColor(getColor());
método draw pen.penUp();
pen.moveTo(getX(),getY());
pen.penDown();
pen.turnTo(0);
50
Exemplo – Desenho Casa
▸ Solução 3 – classe public class Square extends Figure {
public Square() {
this.side = 1;
}
// restante código
}
51
Exemplo – Desenho Casa
@Override
▸ Solução 3 – classe derivada public void draw() {
52
Exemplo – Desenho casa
public class Drawing {
idêntica.
public void draw() {
for (Figure figure : figures) {
figure.draw();
}
}
}
53
Exemplo – Desenho casa
public class Drawing {
▹ Classe Drawing }
figures = new ArrayList<>();
drawing.addFigure(wall);
drawing.addFigure(window);
drawing.addFigure(roof);
drawing.addFigure(sun);
Código idêntico
drawing.draw();
ao da solução 1
}
} 56
Exemplo – Desenho casa
▸ Solução 3 – Diagrama de classes
57
Programação Orientada por Objetos
Herança
▸ Herança de classes
▸ Hierarquias de classes
▸ Principio da substituição
2
Exemplo – Rede Social
▸ Requisitos da rede social:
▹ Um pequeno protótipo com a base para o armazenamento e
apresentação de mensagens.
3
Exemplo – Rede Social
▸ Objetos que pretendemos representar: MessagePost e PhotoPost
4
Exemplo – Rede Social
▸ Classes associadas: MessagePost e PhotoPost
Atributos
Métodos
5
Exemplo – Rede Social
▸ Diagrama de objetos da rede social
6
Exemplo – Rede Social
▸ Diagrama de classes da rede social
7
Exemplo – Rede Social
▸ Classe MessagePost public class MessagePost {
// continua…
currentTimeMillis ???
8
(System.currentTimeMillis – das bibliotecas do Java)
9
Exemplo – Rede Social
▸ Métodos da classe public void like() {
likes++;
}
MessagePost (1/3) public void unlike() {
if (likes > 0) {
likes--;
}
}
10
Exemplo – Rede Social
public void display() {
System.out.println(username);
System.out.println(message);
System.out.print(timeString(timestamp));
if(comments.isEmpty()) {
System.out.println(" No comments.");
}
else {
System.out.println(" " + comments.size() +
" comment(s). Click here to view.");
}
}
11
Exemplo – Rede Social
12
Exemplo – Rede Social
public class PhotoPost {
private String username; Nome do ficheiro com a imagem
private String filename;
private String caption;
private long timestamp;
Legenda da imagem
private int likes;
private ArrayList<String> comments;
// continua…
13
Exemplo – Rede Social
public void like() { ▸ Métodos da classe
likes++;
} PhotoPost (1/3)
public void unlike() {
if (likes > 0) {
likes--;
}
}
public void addComment(String text) {
comments.add(text);
}
public String getImageFile() {
return filename;
}
public String getCaption() {
return caption;
}
14
Exemplo – Rede Social
public long getTimeStamp() {
return timestamp;
▸ Métodos da classe
}
public void display() {
PhotoPost (2/3)
System.out.println(username);
System.out.println(" [" + filename + "]");
System.out.println(" " + caption);
System.out.print(timeString(timestamp));
if(likes > 0) {
System.out.println(" - " + likes + " people like this.");
}
else {
System.out.println();
}
if(comments.isEmpty()) {
System.out.println(" No comments.");
}
else {
System.out.println(" " + comments.size() + " comment(s). Click here to view.");
}
}
15
Exemplo – Rede Social
16
Exemplo – Rede Social
public class NewsFeed {
private ArrayList<MessagePost> messages; ▸ Classe NewsFeed
private ArrayList<PhotoPost> photos;
public NewsFeed() {
messages = new ArrayList<MessagePost>();
photos = new ArrayList<PhotoPost>();
}
// continua…
17
Exemplo – Rede Social
// continuação da classe Newsfeed… ▸ Classe NewsFeed
public void show() {
// display all text posts
for(MessagePost message : messages) {
message.display();
System.out.println(); // empty line between posts
}
18
Exemplo – Rede Social
▸ Problemas do protótipo criado:
▹ Duplicação de código
Atributos
Métodos
21
Exemplo – Rede Social
▸ Solução: Herança de classes Constroi-se uma
nova classe (Post)
com o código
comum.
22
Herança de classes
Herança de classes
▸ É uma técnica usada em Programação Orientada por Objetos que vai permitir a reutilização de código.
▹ Define-se uma classe com o código comum.
▹ Criam-se outras classes com base na classe anterior que reutilizam esse código.
▹ A classe criada inicialmente é a superclasse e as classes que vão reutilizar essa classe são as subclasses.
23
Exemplo – Rede Social
▸ Solução: usar a Herança de classes
25
Exemplo – Rede Social
26
Exemplo – Rede Social
public class MessagePost extends Post {
private String message; ▸ Subclasses –
27
Exemplo – Rede Social
▸ Herança de classes em Java
Atributos
idênticos
28
Exemplo – Rede Social
▸ Herança de classes em Java
Métodos
idênticos
Mesma
utilização
30
Herança de classes
▸ Herança de classes
32
Herança – Hierarquia de Classes - vocabulário
Animal é superclasse
direta (classe base ou
classe pai) de Mammal e
Bird, e é super classe
Animal
indireta de Dog, Cat e Cow
Mammal é subclasse
direta (classe derivada ou
classe filha) de Animal e
super classe direta (base
Mammal Bird
ou pai) de Dog, Cat e Cow
33
Herança
▸ As subclasses ou classes derivadas vão herdar todos os atributos e métodos da superclasse ou classe
base.
▸ As subclasses não herdam os construtores da superclasse
34
Construtores em Herança
▸ Herança de Classes
Herança
▸ As subclasses não herdam os construtores da superclasse
public class Post {
private String username;
private long timestamp;
private int likes;
private ArrayList<String> comments;
37
Exemplo – Rede Social
public class Post {
private String username; ▸ Construtores em herança –
private long timestamp;
private int likes; classe Post
private ArrayList<String> comments;
// métodos omitidos
}
38
Exemplo – Rede Social
▸ Construtores em herança
public class MessagePost extends Post {
private String message; – classe MessagePost
public MessagePost(String author, String text) {
super(author);
message = text;
} Chamada ao
construtor da
// métodos omitidos superclasse (Post)
}
39
Construtores em herança
▸ Construtores em herança
▹ O construtor da subclasse deve incluir sempre uma chamada ao construtor da superclasse
▹ Se não for incluída o compilador coloca automaticamente uma chamada ao construtor sem
argumentos da superclasse: super();
▹ Apenas resulta se a superclasse tiver um construtor sem argumentos
// métodos omitidos
Primeira instrução do construtor
}
40
Herança
public class Post {
private String username;
▸ As subclasses não herdam
private long timestamp;
private int likes;
os construtores da
private ArrayList<String> comments;
superclasse
public Post(String author) {
username = author;
timestamp = System.currentTimeMillis();
likes = 0;
comments = new ArrayList<String>();
}
}
}
41
Herança por Extensão
▸ Herança de Classes
Modificadores de acesso do Java
▸ Membros public (símbolo + nos diagramas de classe): Se os membros são declarados como públicos
dentro de uma classe, então estes membros são acessíveis às classes que estão dentro e fora do
pacote onde esta classe é visível. Este é o menos restritivo de todos os modificadores de
acessibilidade.
▸ Membros protected (símbolo # nos diagramas de classe) : se os membros de uma classe são
declarados como protegidos, eles estarão acessíveis a todas as classes do pacote e a todas as
subclasses desta classe em qualquer pacote em que essa classe esteja visível.
▸ Membros default (nenhum símbolo) : quando nenhum modificador de acessibilidade é especificado para
o membro, ele é implicitamente declarado como visibilidade por defeito. Eles são acessíveis apenas
para as outras classes no pacote da classe.
▸ Membros private (símbolo - nos diagramas de classe) : Este é o mais restritivo de todos os
modificadores de acessibilidade. Esses membros são acessíveis apenas dentro desta classe. Eles não
são acessíveis a partir de nenhuma outra classe dentro do pacote da classe.
43
Exemplo – Rede Social
▸ Adição de outro tipo de Posts – EventPost
*métodos omitidos
Nova classe
EventPost.
44
Exemplo – Rede Social
▸ Hierarquias mais complexas
*métodos omitidos
45
Exemplo – Rede Social
• Simplifica a manutenção
46
Principio da substituição
▸ Herança de Classes
Principio da Substituição
Subclasses e Subtipos
▸ Uma classe define um tipo
▸ Uma subclasse define um subtipo
▸ Sempre que é necessário um objeto de uma classe, pode-se usar em vez disso um objeto
de uma subclasse:
▹ Chama-se principio da substituição
▹ Exemplo
Post post = new MessagePost("João", "Olá Mundo");
49
Principio da Substituição
public class NewsFeed {
▸ Principio da substituição
public void addPost(Post post) aplicado à passagem de
{
... parâmetros
}
}
feed.addPost(photo);
Objetos de subclasses
feed.addPost(message);
podem ser usados como
parâmetros atuais para
superclasses
50
Exemplo – Rede Social
public class NewsFeed {
private ArrayList<Post> posts;
▸ Nova classe NewsFeed
public NewsFeed() {
posts = new ArrayList<Post>();
}
51
Exemplo – Rede Social
▸ Diagrama de objetos
52
Exemplo – Rede Social
▸ Diagrama de classes
53
Exemplo – Rede Social
▸ Antiga classe versus nova classe NewsFeed
public class NewsFeed { public class NewsFeed {
private ArrayList<MessagePost> messages; private ArrayList<Post> posts;
private ArrayList<PhotoPost> photos;
public NewsFeed() {
public NewsFeed() {
messages = new ArrayList<MessagePost>();
posts = new ArrayList<Post>();
photos = new ArrayList<PhotoPost>();
} }
public void addMessagePost(MessagePost message) {
messages.add(message); public void addPost(Post post) {
} posts.add(post);
public void addPhotoPost(PhotoPost photo) { }
photos.add(photo);
}
public void show() {
public void show() {
for(Post post : posts) {
for(MessagePost message : messages) {
message.display(); post.display();
System.out.println(); System.out.println();
} }
for(PhotoPost photo : photos) { }
photo.display(); }
System.out.println();
}
}
}
54
Bibliografia
55
Programação Orientada por Objetos
Herança de
classes -
exemplo
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Redefinição de métodos
▸ A Classe Object
2
Exemplo – Xadrez
▸ Requisitos do protótipo:
▹ Representar os componentes do jogo sem
implementar as regras ou o desenrolar do jogo.
▹ Representar as peças: peão, torre, cavalo, rei,
rainha e bispo.
▹ Representar o tabuleiro de jogo com as posições.
▹ Deve ser possível obter em texto a posição de
cada peça usando a notação algébrica (ex: e5 –
peão na casa e5, ou Te7 – torre na casa e7).
3
Exemplo – Xadrez
Representação 1
▹ Cada peça poderá ser representada
por uma classe
▹ Peças: peão, torre, cavalo, rei, rainha
e bispo.
▹ O tabuleiro de jogo corresponde a
outra classe.
4
Exemplo – Xadrez
Representação 1
▹ Cada peça poderá ser
representada por uma classe
▹ Peças: peão, torre, cavalo, rei,
rainha e bispo.
▹ O tabuleiro de jogo
corresponde a outra classe.
5
Exemplo – Xadrez
▸ Representação 1 – Classes Pawn e Rook
public class Pawn { public class Rook {
public Pawn(Colour colour, Position position) { public Rook(Colour colour, Position position) {
this.colour = colour; this.colour = colour;
if (position != null) { if (position != null) {
this.position = position; this.position = position;
} else { } else {
this.position = new Position(); this.position = new Position();
} }
} }
7
Exemplo – Xadrez
8
Exemplo – Xadrez
Representação 2
▹ Criar uma classe peça que
representa qualquer peça
▹ Usar um atributo PieceType que
determina qual a peça
representada.
▹ O tabuleiro de jogo corresponde a
outra classe.
9
Exemplo – Xadrez
▸ Representação 2 – Classe Piece
public class Piece { public String toString() {
String text = "";
private Colour colour; switch(pieceType){
private Position position; case ROOK:
private PieceType pieceType; text += 'T';
break;
public Piece(PieceType pieceType, case KNIGHT:
Colour colour, Position position) { text += 'C';
this.pieceType = pieceType; break;
this.colour = colour;
case BISHOP:
if (position != null) {
text += 'B';
this.position = position;
} else { break;
this.position = new Position(); case QUEEN:
} text += 'D';
} break;
case KING:
public Colour getColour() { ... } text += 'R';
public PieceType getPieceType() { ... } break;
public void setPieceType(PieceType pieceType) { ... } }
public Position getPosition() { ... } text += position.toString();
public void setPosition(char x, int y) { ... } return text;
public void setPosition(Position position) { ... } }
public void setY(int y) { ... }
public char getX() { ... }
public int getY() { ... } public String getName() { ... }
}
}
10
Exemplo – Xadrez
▸ Representação 2 – private void setup() {
Classe ChessBoard
for (char x = 'a'; x <= 'h'; x++) {
pieces.add(new Piece(PieceType.PAWN, Colour.WHITE, new Position(x, 2)));
pieces.add(new Piece(PieceType.PAWN, Colour.BLACK, new Position(x, 7)));
}
int line = 1;
Colour colour = Colour.WHITE;
pieces.add(new Piece(PieceType.ROOK, colour, new Position('a', line)));
pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('b', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('c', line)));
pieces.add(new Piece(PieceType.QUEEN, colour, new Position('d', line)));
public class Chessboard { pieces.add(new Piece(PieceType.KING, colour, new Position('e', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('f', line)));
ArrayList<Piece> pieces; pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('g', line)));
pieces.add(new Piece(PieceType.ROOK, colour, new Position('h', line)));
public Chessboard() { line = 8;
pieces = new ArrayList<>(); colour = Colour.BLACK;
setup(); pieces.add(new Piece(PieceType.ROOK, colour, new Position('a', line)));
} pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('b', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('c', line)));
pieces.add(new Piece(PieceType.QUEEN, colour, new Position('d', line)));
pieces.add(new Piece(PieceType.KING, colour, new Position('e', line)));
pieces.add(new Piece(PieceType.BISHOP, colour, new Position('f', line)));
pieces.add(new Piece(PieceType.KNIGHT, colour, new Position('g', line)));
pieces.add(new Piece(PieceType.ROOK, colour, new Position('h', line)));
}
}
11
Exemplo – Xadrez
12
Exemplo – Xadrez
▸ Solução:
13
Exemplo – Xadrez
▸ Requisitos do protótipo:
▹ Representar os componentes do jogo sem
implementar as regras ou o desenrolar do jogo.
▹ Representar as peças: peão, torre, cavalo, rei,
rainha e bispo.
▹ Representar o tabuleiro de jogo com as
posições.
▹ Deve ser possível obter em texto a posição de
cada peça usando a notação algébrica (ex: e5 –
peão na casa e5, ou Te7 – torre na casa e7). 14
Exemplo – Xadrez (3)
▸ Representação 3 – Usar a herança:
▹ Definir cada uma das peças como uma subclasse da classe Piece
16
Exemplo – Xadrez (3)
▸ Exemplo de objetos da representação 1
Atributos
idênticos
Métodos
idênticos
17
Exemplo – Xadrez (3)
public class Piece {
19
Exemplo – Xadrez (3)
public void setY(int y) {
position.setY(y);
}
▸ Classe Piece – métodos (2/2)
public char getX() {
return position.getX();
}
20
Exemplo – Xadrez (3)
▸ Classe Rook
21
Classes Pawn e Rook
27
Exemplo – Xadrez (3)
▸ Classes Queen, King, Bishop, Knight
▹ Omitidas: são semelhantes às anteriores public class Chessboard {
▸ Classe Chessboard
ArrayList<Piece> pieces;
public Chessboard() {
pieces = new ArrayList<>();
setup();
Apenas uma lista para }
guardar as várias peças
// métodos omitidos
}
28
private void setup() {
Exemplo –
for (char x = 'a'; x <= 'h'; x++) {
pieces.add(new Pawn(Colour.WHITE, new Position(x, 2)));
pieces.add(new Pawn(Colour.BLACK, new Position(x, 7)));
}
int line = 1;
Xadrez (3)
Colour colour = Colour.WHITE;
pieces.add(new Rook(colour, new Position('a', line)));
pieces.add(new Knight(colour, new Position('b', line)));
pieces.add(new Bishop(colour, new Position('c', line)));
pieces.add(new Queen(colour, new Position('d', line)));
pieces.add(new King(colour, new Position('e', line)));
pieces.add(new Bishop(colour, new Position('f', line)));
pieces.add(new Knight(colour, new Position('g', line)));
pieces.add(new Rook(colour, new Position('h', line)));
▸ Classe Chessboard –
line = 8;
método setup colour = Colour.BLACK;
pieces.add(new Rook(colour, new Position('a', line)));
pieces.add(new Knight(colour, new Position('b', line)));
pieces.add(new Bishop(colour, new Position('c', line)));
pieces.add(new Queen(colour, new Position('d', line)));
A inicialização tem pieces.add(new King(colour, new Position('e', line)));
de ser feita com o pieces.add(new Bishop(colour, new Position('f', line)));
pieces.add(new Knight(colour, new Position('g', line)));
mesmo detalhe pieces.add(new Rook(colour, new Position('h', line)));
}
29
Exemplo – Formas Geométricas
Requisitos do programa:
30
Exemplo – Formas Geométricas
radius side
x,y
x,y
Circle Square
31
Exemplo – Formas Geométricas
32
Exemplo – Formas Geométricas
public class Circle { public int getX() {
private int x, y;
return x;
private int radius;
}
public Circle() {
public void setX(int x) {
this.x = 0;
this.x = x;
this.y = 0;
this. radius = 1; }
} public int getY() {
public Circle(int x, int y, int radius) { return y;
this.x = x;
}
this.y = y;
public void setY(int y) {
this. radius = radius;
this.y = y;
}
}
public int getRadius() {
return radius; public void move( int dx, int dy ) {
} x += dx; y += dy;
public void setRadius(int raio) { }
this. radius = radius; }
}
33
Exemplo – Formas Geométricas
public class Square { public int getX() {
private int x, y;
return x;
private int side;
}
public Square() {
this.x = 0; public void setX(int x) {
this.y = 0; this.x = x;
this.side = 1; }
}
public int getY() {
public Square(int x, int y, int side) {
return y;
this.x = x;
this.y = y; }
this.side = side; public void setY(int y) {
}
this.y = y;
public int getSide() {
}
return side;
} public void move( int dx, int dy ) {
public void setSide(int side) { x += dx; y += dy;
this.side = side; }
}
}
34
public class Program {
public static void main(String[] args) {
Circle circle = new Circle(1, 1, 23);
35
Exemplo – Formas Geométricas
▸ As classes Circle e Square têm em comum alguns dos atributos e métodos
(código duplicado):
▹ 2 atributos (x e y)
36
Exemplo – Formas Geométricas
37
Exemplo – Formas Geométricas
public int getX() {
41
Exemplo – Formas Geométricas
42
Exemplo – Formas Geométricas
Acrescenta os atributos x2 e y2 para a
representação do segundo ponto do
segmento de retas
public class LineSegment extends GeometricShape {
public int getX2() {
private int x2, y2;
return x2;
public LineSegment() {
}
super(0, 0);
public void setX2(int x2) {
this.x2 = 1;
this.x2 = x2;
this.y2 = 1;
}
}
public int getY2() {
public LineSegment(int x, int y, int x2, int y2) {
return y2;
super(x, y);
}
this.x2 = x2;
Existe um método que public void setY2(int y2) {
this.y2 = y2; é herdado mas não é
this.y2 = y2;
} adequado nesta classe.
Qual? }
}
43
Herança – Redefinição de Métodos
▸ O método:
public void move( int dx, int dy ) {
x += dx; y += dy;
}
▹ Este método não funciona corretamente para objetos da classe LineSegment.
▹ A solução é redefinir este método nesta classe.
▹ Para redefinir um método basta defini-lo novamente no corpo da subclasse:
@Override
public void move( int dx, int dy ) {
super.move(dx, dy);
x2 += dx; y2 += dy;
}
}
44
Exemplo – Formas Geométricas
45
Considerações Finais
▸ Herança de classes
46
Herança (is-a) – Generalização vs Especialização
Versus …
47
Herança (is-a) – Generalização vs Especialização
▸ Na prática a herança utiliza-se por generalização e por especialização de classes
48
Herança (is-a) – Generalização vs Especialização
o
lizaçã
a
ner
Ge
49
Herança (is-a) – Generalização vs Especialização
Es
pe
cia
liz
aç
ão
50
Classe Object
▸ A classe Object é uma classe do Java, que está no topo da hierarquia e da
qual todas as outras são subclasses diretas ou indiretas.
▹ Todas as classes são uma especialização de Object, são todas um
tipo de objeto.
▹ Quando uma classe não deriva de outra o compilador de Java coloca-
a a derivar de Object (é acrescentado extends Object).
▹ A classe Object define um conjunto de métodos que são herdados
por todas as classes, entre eles estão os métodos: toString, equals
e hashCode utilizados antes.
▹ Por isso quando se coloca um destes métodos numa classe, na
prática está-se a redefinir o método herdado, sendo então
necessário colocar @Override antes da redefinição
51
Exemplo – Xadrez (3)
▸ Classe Object
52
Bibliografia
53
Programação Orientada por Objetos
Polimorfismo
▸ Principio da Substituição
▸ Tipos Estáticos e Tipos Dinâmicos
▸ Polimorfismo
▸ Exemplo Formas Geométricas
2
Principio da Substituição
▸ Polimorfismo
3
Exemplo – Rede Social
4
Exemplo – Rede Social
▸ Solução com herança de classes:
Classe base Post
com o código
comum
Classes derivadas
MessagePost e
PhotoPost
5
Exemplo – Rede Social
▸ Exemplo de utilização
O texto da
mensagem não é
mostrado
6
Exemplo – Rede Social
▸ Exemplo de utilização
7
Exemplo – Rede Social
▸ Exemplo de utilização
public class Post {
private String username;
private long timestamp;
private int likes;
A informação mostrada está
private ArrayList<String> comments; incompleta para as classes
MessagePost e
// restante código omitido PhotoPost
public void display() {
System.out.println(username);
System.out.print(timeString(timestamp));
if(likes > 0) {
System.out.println(" - " + likes + " people like this.");
}
else {
System.out.println();
} Solução:
if(comments.isEmpty()) { Redefinir o método nas
System.out.println(" No comments."); classes derivadas
}
else {
System.out.println(" " + comments.size() +
" comment(s). Click here to view.");
}
}
} 8
Exemplo – Rede Social
public class MessagePost extends Post {
private String message;
▸ Exemplo de utilização
// restantes métodos omitidos
@Override
public void display() {
super.display();
System.out.println(message);
}
}
Acrescenta o texto da
mensagem no caso de
objetos MessagePost
10
Principio da Substituição
▸ Subclasses e Subtipos
▸ Uma classe define um tipo
▸ Uma subclasse define um subtipo
▸ Sempre que é necessário um objeto de uma classe pode-se usar em vez disso um
objeto duma subclasse:
▹ Chama-se principio da substituição
▹ Exemplo
Post post = new MessagePost("João", "Olá Mundo");
display de
MessagePost
display de PhotoPost
12
Principio da Substituição
▸ Exemplo de utilização
13
Principio da Substituição
▸ Exemplo de utilização
14
Tipos Estáticos e
Dinâmicos
▸ Polimorfismo
15
Exemplo – Rede Social
16
Exemplo – Rede Social
▸ Classe MessagePost
// métodos omitidos
O método requerido
public String getText() { já existia na classe
return message; MessagePost
}
}
17
Exemplo – Rede Social
▸ Classe PhotoPost
}
18
Exemplo – Rede Social
▸ Superclasse – Post
19
Principio da Substituição
▸ Exemplo de utilização – método getText
Erro???
20
Tipos Estáticos e Tipos dinâmicos
21
Tipos Estáticos e Tipos dinâmicos
▸ O tipo declarado de uma variável é o seu tipo estático (static type)
▸ O tipo do objeto referido pela variável é o seu tipo dinâmico (dynamic type)
▸ O compilador verifica sempre se existem erros nos tipos estáticos.
▹ Não é possível referir objetos que não sejam da classe do tipo estático ou de uma das classes
derivadas do mesmo.
▹ Não é possível chamar métodos para uma variável que não existam no seu tipo estático. Ou seja, que
não existam na classe declarada.
22
Tipos Estáticos e Tipos dinâmicos
23
Tipos Estáticos e Tipos dinâmicos
No caso do método
display não há
problema porque existe
na classe base e nas
classes derivadas
Satisfaz a verificação
estática (e dinâmica)
do tipo
24
Tipos Estáticos e Tipos dinâmicos
O método getText
só existe nas
classes derivadas
Não satisfaz a
verificação estática
do tipo
25
Tipos Estáticos e Tipos dinâmicos
26
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime)
27
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime) – procura do método a executar:
O método display a
executar apenas pode
ser o que está em Neste exemplo não
PhotoPost existe herança
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime) – procura do método a executar:
31
Polimorfismo
▸ Polimorfismo
32
Polimorfismo
▸ Quando executamos um método, o método que é executado depende da classe do objeto que o
executa. Neste caso dizemos que temos polimorfismo de métodos.
▹ Um método várias (poli) formas (Morfo) de resposta
▹ O método display tem várias formas de resposta, dentro da classe MessagePost tem uma
forma, dentro da classe PhotoPost tem outra forma.
▹ O método que realmente é chamado depende do tipo do objeto em tempo de execução (o tipo dinâmico)
33
Polimorfismo
▸ Para solucionar este erro ter-se-ia que criar o método getText na classe
Post mesmo que não fizesse nada
public class Post {
▸ Na execução, o método getText executado vai corresponder ao método getText da classe do objeto
public class PhotoPost extends Post {
public class MessagePost extends Post { private String filename;
private String message; private String caption;
// código omitido // código omitido
@Override @Override
public String getText() { public String getText() {
return message; return caption;
} }
} }
35
Polimorfismo
▸ Poliformismo
36
▸ Polimorfismo
Exemplo Formas
geométricas
37
Exemplo – Formas Geométricas
▸ Requisitos do programa:
▹ Desenho de formas geométricas.
▹ Representar círculos, quadrados e retângulos.
▹ Deve ser possível saber as dimensões e a posição de cada um deles.
▹ Deve ser possível deslocá-los.
38
Polimorfismo - exemplo
▸ Exemplo de formas geométricas
raio radiu x,
s y
x,y
x,y
x,y
lad
x2,y o
2
Círculo Retângulo Quadrado
39
Polimorfismo - exemplo
40
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
42
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
public class Shape { public circle() { this.radius = 1; }
private int x, y; public circle(int x, int y, int radius) {
super(x, y); this.radius = radius; }
public Shape () { public int getRadius() { return radius; }
x = 0; public void setRadius(int radius) { this.radius = radius; }
y = 0; }
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; public Rectangle() {this.x2 = 0; this.y2 = 0; }
this.y = y; public Rectangle(int x, int y, int x2, int y2) {
formas geométricas!!!
public void setY2(int y2) { this.y2 = y2; }
}
}
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
private int side;
} public Square() {this.side = 1;}
public int getY() { public Square(int x, int y, int side) {
return y; super(x, y, x+side, y+side); this.side = side;}
public int getSide() {return side;}
}
public void setSide(int side) { this.side = side;
public void setY(int y) {
setX2(getX() + side);setY2(getY() - side); }
this.y = y; @Override public void setX(int x) { super.setX(x);
} setX2(getX() + side); } ... }
} 43
Polimorfismo - exemplo
public class Shape {
public class circle extends Shape {
private int radius;
@Override
private int x, y;
public double getArea() {
return Math.PI*radius*radius;
public Shape () {
getArea do
}
círculo
x = 0;
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; public Rectangle() {this.x2 = 0; this.y2 = 0; }
this.y = y; public Rectangle(int x, int y, int x2, int y2) {
super(x, y); this.x2 = x2;this.y2 = y2; }
}
public int getX2() { return x2; }
public int getX() { public void setX2(int x2) { this.x2 = x2; }
return x; public int getY2() { return y2; }
public void setY2(int y2) { this.y2 = y2; }
}
}
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
private int side;
} public Square() {this.side = 1;}
public int getY() { public Square(int x, int y, int side) {
return y; super(x, y, x+side, y+side); this.side = side;}
public int getSide() {return side;}
}
public void setSide(int side) { this.side = side;
public void setY(int y) {
setX2(getX() + side);setY2(getY() - side); }
this.y = y; @Override public void setX(int x) { super.setX(x);
} setX2(getX() + side); } ... }
} 44
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
public class Shape {
@Override
private int x, y;
public double getArea() {
return Math.PI*radius*radius;
public Shape () {
x = 0; }
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; @Override
this.y = y; public double getArea() {
} double dx = x2 - getX();
return Math.PI*radius*radius;
public Shape () {
x = 0; }
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; @Override
this.y = y; public double getArea() {
} double dx = x2 - getX();
double dy = y2 - getY();
public int getX() {
return Math.abs(dx * dy);
return x; }
} } // Restante código omitido
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
getArea do quadrado private int side;
não é necessária, o
}
public int getY() {
return y;
método herdado serve
} // Restante código omitido
}
public void setY(int y) {
this.y = y;
}
} 46
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
@Override
public class Shape {
public double getArea() {
private int x, y;
return Math.PI*radius*radius;
}
public Shape () {
x = 0; } // Restante código omitido
y = 0;
public class Rectangle extends Shape {
}
private int x2, y2;
public Shape (int x, int y) {
return y;
} } // Restante código omitido
this.y = y;
}
} 47
public class circle extends Shape {
private int radius;
polimorfismo funcionar.
private int side;
return 0.0;
}
} 48
Polimorfismo - exemplo
Usamos o principio da
public class Main{ substituição para guardar
public static void main(String[] args) { as diferentes formas
Shape[] shapes; geométricas no mesmo
shapes = new Shape[6]; array
shapes[0] = new circle(4, 8, 3);
shapes[1] = new circle(28, 10, 4);
shapes[2] = new Rectangle(3, 0, 5, 6);
shapes[3] = new Rectangle(11, 0, 23, 6);
shapes[4] = new Rectangle(18, 0, 21, 4); Calculamos a área
shapes[5] = new Square(13, 2, 2); aplicando o
double totalArea = 0; polimorfismo. Cada
forma geométrica
for (int i=0; i < shapes.length; i++) { retorna a sua área
totalArea += shapes[i].getArea();
}
System.out.println("Area Total: " + totalArea);
}
}
49
Polimorfismo - exemplo
public class Main{
public static void main(String[] args) {
ArrayList<Shape> shapes = new ArrayList<>();
shapes.add(new circle(4, 8, 3));
shapes.add(new circle(28, 10, 4));
shapes.add(new Rectangle(3, 0, 5, 6));
Alternativa
shapes.add(new Rectangle(11, 0, 23, 6)); com listas!
shapes.add(new Rectangle(18, 0, 21, 4));
shapes.add(new Square(13, 2, 2));
double totalArea = 0;
50
Bibliografia
51
Programação Orientada por Objetos
Polimorfismo
▸ Principio da Substituição
▸ Tipos Estáticos e Tipos Dinâmicos
▸ Polimorfismo
▸ Exemplo Formas Geométricas
2
Principio da Substituição
▸ Polimorfismo
3
Exemplo – Rede Social
4
Exemplo – Rede Social
▸ Solução com herança de classes:
Classe base Post
com o código
comum
Classes derivadas
MessagePost e
PhotoPost
5
Exemplo – Rede Social
▸ Exemplo de utilização
O texto da
mensagem não é
mostrado
6
Exemplo – Rede Social
▸ Exemplo de utilização
7
Exemplo – Rede Social
▸ Exemplo de utilização
public class Post {
private String username;
private long timestamp;
private int likes;
A informação mostrada está
private ArrayList<String> comments; incompleta para as classes
MessagePost e
// restante código omitido PhotoPost
public void display() {
System.out.println(username);
System.out.print(timeString(timestamp));
if(likes > 0) {
System.out.println(" - " + likes + " people like this.");
}
else {
System.out.println();
} Solução:
if(comments.isEmpty()) { Redefinir o método nas
System.out.println(" No comments."); classes derivadas
}
else {
System.out.println(" " + comments.size() +
" comment(s). Click here to view.");
}
}
} 8
Exemplo – Rede Social
public class MessagePost extends Post {
private String message;
▸ Exemplo de utilização
// restantes métodos omitidos
@Override
public void display() {
super.display();
System.out.println(message);
}
}
Acrescenta o texto da
mensagem no caso de
objetos MessagePost
10
Principio da Substituição
▸ Subclasses e Subtipos
▸ Uma classe define um tipo
▸ Uma subclasse define um subtipo
▸ Sempre que é necessário um objeto de uma classe pode-se usar em vez disso um
objeto duma subclasse:
▹ Chama-se principio da substituição
▹ Exemplo
Post post = new MessagePost("João", "Olá Mundo");
display de
MessagePost
display de PhotoPost
12
Principio da Substituição
▸ Exemplo de utilização
13
Principio da Substituição
▸ Exemplo de utilização
14
Tipos Estáticos e
Dinâmicos
▸ Polimorfismo
15
Exemplo – Rede Social
16
Exemplo – Rede Social
▸ Classe MessagePost
// métodos omitidos
O método requerido
public String getText() { já existia na classe
return message; MessagePost
}
}
17
Exemplo – Rede Social
▸ Classe PhotoPost
}
18
Exemplo – Rede Social
▸ Superclasse – Post
19
Principio da Substituição
▸ Exemplo de utilização – método getText
Erro???
20
Tipos Estáticos e Tipos dinâmicos
21
Tipos Estáticos e Tipos dinâmicos
▸ O tipo declarado de uma variável é o seu tipo estático (static type)
▸ O tipo do objeto referido pela variável é o seu tipo dinâmico (dynamic type)
▸ O compilador verifica sempre se existem erros nos tipos estáticos.
▹ Não é possível referir objetos que não sejam da classe do tipo estático ou de uma das classes
derivadas do mesmo.
▹ Não é possível chamar métodos para uma variável que não existam no seu tipo estático. Ou seja, que
não existam na classe declarada.
22
Tipos Estáticos e Tipos dinâmicos
23
Tipos Estáticos e Tipos dinâmicos
No caso do método
display não há
problema porque existe
na classe base e nas
classes derivadas
Satisfaz a verificação
estática (e dinâmica)
do tipo
24
Tipos Estáticos e Tipos dinâmicos
O método getText
só existe nas
classes derivadas
Não satisfaz a
verificação estática
do tipo
25
Tipos Estáticos e Tipos dinâmicos
26
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime)
27
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime) – procura do método a executar:
O método display a
executar apenas pode
ser o que está em Neste exemplo não
PhotoPost existe herança
Tipos Estáticos e Tipos dinâmicos
▸ Em tempo de execução (runTime) – procura do método a executar:
31
Polimorfismo
▸ Polimorfismo
32
Polimorfismo
▸ Quando executamos um método, o método que é executado depende da classe do objeto que o
executa. Neste caso dizemos que temos polimorfismo de métodos.
▹ Um método várias (poli) formas (Morfo) de resposta
▹ O método display tem várias formas de resposta, dentro da classe MessagePost tem uma
forma, dentro da classe PhotoPost tem outra forma.
▹ O método que realmente é chamado depende do tipo do objeto em tempo de execução (o tipo dinâmico)
33
Polimorfismo
▸ Para solucionar este erro ter-se-ia que criar o método getText na classe
Post mesmo que não fizesse nada
public class Post {
▸ Na execução, o método getText executado vai corresponder ao método getText da classe do objeto
public class PhotoPost extends Post {
public class MessagePost extends Post { private String filename;
private String message; private String caption;
// código omitido // código omitido
@Override @Override
public String getText() { public String getText() {
return message; return caption;
} }
} }
35
Polimorfismo
▸ Poliformismo
36
▸ Polimorfismo
Exemplo Formas
geométricas
37
Exemplo – Formas Geométricas
▸ Requisitos do programa:
▹ Desenho de formas geométricas.
▹ Representar círculos, quadrados e retângulos.
▹ Deve ser possível saber as dimensões e a posição de cada um deles.
▹ Deve ser possível deslocá-los.
38
Polimorfismo - exemplo
▸ Exemplo de formas geométricas
raio radiu x,
s y
x,y
x,y
x,y
lad
x2,y o
2
Círculo Retângulo Quadrado
39
Polimorfismo - exemplo
40
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
42
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
public class Shape { public circle() { this.radius = 1; }
private int x, y; public circle(int x, int y, int radius) {
super(x, y); this.radius = radius; }
public Shape () { public int getRadius() { return radius; }
x = 0; public void setRadius(int radius) { this.radius = radius; }
y = 0; }
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; public Rectangle() {this.x2 = 0; this.y2 = 0; }
this.y = y; public Rectangle(int x, int y, int x2, int y2) {
formas geométricas!!!
public void setY2(int y2) { this.y2 = y2; }
}
}
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
private int side;
} public Square() {this.side = 1;}
public int getY() { public Square(int x, int y, int side) {
return y; super(x, y, x+side, y+side); this.side = side;}
public int getSide() {return side;}
}
public void setSide(int side) { this.side = side;
public void setY(int y) {
setX2(getX() + side);setY2(getY() - side); }
this.y = y; @Override public void setX(int x) { super.setX(x);
} setX2(getX() + side); } ... }
} 43
Polimorfismo - exemplo
public class Shape {
public class circle extends Shape {
private int radius;
@Override
private int x, y;
public double getArea() {
return Math.PI*radius*radius;
public Shape () {
getArea do
}
círculo
x = 0;
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; public Rectangle() {this.x2 = 0; this.y2 = 0; }
this.y = y; public Rectangle(int x, int y, int x2, int y2) {
super(x, y); this.x2 = x2;this.y2 = y2; }
}
public int getX2() { return x2; }
public int getX() { public void setX2(int x2) { this.x2 = x2; }
return x; public int getY2() { return y2; }
public void setY2(int y2) { this.y2 = y2; }
}
}
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
private int side;
} public Square() {this.side = 1;}
public int getY() { public Square(int x, int y, int side) {
return y; super(x, y, x+side, y+side); this.side = side;}
public int getSide() {return side;}
}
public void setSide(int side) { this.side = side;
public void setY(int y) {
setX2(getX() + side);setY2(getY() - side); }
this.y = y; @Override public void setX(int x) { super.setX(x);
} setX2(getX() + side); } ... }
} 44
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
public class Shape {
@Override
private int x, y;
public double getArea() {
return Math.PI*radius*radius;
public Shape () {
x = 0; }
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; @Override
this.y = y; public double getArea() {
} double dx = x2 - getX();
return Math.PI*radius*radius;
public Shape () {
x = 0; }
y = 0; } // Restante código omitido
}
public class Rectangle extends Shape {
public Shape (int x, int y) { private int x2, y2;
this.x = x; @Override
this.y = y; public double getArea() {
} double dx = x2 - getX();
double dy = y2 - getY();
public int getX() {
return Math.abs(dx * dy);
return x; }
} } // Restante código omitido
public void setX(int x) {
public class Square extends Rectangle {
this.x = x;
getArea do quadrado private int side;
não é necessária, o
}
public int getY() {
return y;
método herdado serve
} // Restante código omitido
}
public void setY(int y) {
this.y = y;
}
} 46
Polimorfismo - exemplo public class circle extends Shape {
private int radius;
@Override
public class Shape {
public double getArea() {
private int x, y;
return Math.PI*radius*radius;
}
public Shape () {
x = 0; } // Restante código omitido
y = 0;
public class Rectangle extends Shape {
}
private int x2, y2;
public Shape (int x, int y) {
return y;
} } // Restante código omitido
this.y = y;
}
} 47
public class circle extends Shape {
private int radius;
polimorfismo funcionar.
private int side;
return 0.0;
}
} 48
Polimorfismo - exemplo
Usamos o principio da
public class Main{ substituição para guardar
public static void main(String[] args) { as diferentes formas
Shape[] shapes; geométricas no mesmo
shapes = new Shape[6]; array
shapes[0] = new circle(4, 8, 3);
shapes[1] = new circle(28, 10, 4);
shapes[2] = new Rectangle(3, 0, 5, 6);
shapes[3] = new Rectangle(11, 0, 23, 6);
shapes[4] = new Rectangle(18, 0, 21, 4); Calculamos a área
shapes[5] = new Square(13, 2, 2); aplicando o
double totalArea = 0; polimorfismo. Cada
forma geométrica
for (int i=0; i < shapes.length; i++) { retorna a sua área
totalArea += shapes[i].getArea();
}
System.out.println("Area Total: " + totalArea);
}
}
49
Polimorfismo - exemplo
public class Main{
public static void main(String[] args) {
ArrayList<Shape> shapes = new ArrayList<>();
shapes.add(new circle(4, 8, 3));
shapes.add(new circle(28, 10, 4));
shapes.add(new Rectangle(3, 0, 5, 6));
Alternativa
shapes.add(new Rectangle(11, 0, 23, 6)); com listas!
shapes.add(new Rectangle(18, 0, 21, 4));
shapes.add(new Square(13, 2, 2));
double totalArea = 0;
50
Bibliografia
51
Programação Orientada por Objetos
Polimorfismo
- Exemplo
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Organização de Código
2
Desenho Casa –
Solução 1
▸ Polimorfismo
3
Exemplo – Desenho Casa
▸ Requisitos do desenho (Revisitado):
▹ O desenho é composto por quadrados, triângulos, círculos e
retângulos.
▹ Cada uma das formas geométricas tem uma cor e uma
posição.
▹ O desenho reutiliza as classes Pen e Canvas do ambiente
gráfico. Neste caso as figuras são desenhadas apenas com as
linhas de contorno.
▹ Deverá ser possível criar facilmente outros desenhos com as
figuras geométricas existentes (circulo, quadrado, triângulo e
retângulo).
4
Exemplo – Desenho Casa
Foram criadas 2 soluções:
▸ Solução 1:
Circle, Triangle.
▹ Uma classe Figure que pode ser qualquer das figuras existentes.
▹ Uma classe Drawing para o desenho que guarda uma lista de figuras.
5
Exemplo – Desenho casa
▸ Classe Position para representar a posição das figuras:
public class Position { public int getX() {
return x;
private int x; }
private int y;
public int getY() {
public Position() { return y;
x = 0; }
y = 0;
} public void setX(int x) {
this.x = x;
public Position(int x, int y) { }
this.x = x;
this.y = y; public void setY(int y) {
} this.y = y;
}
// continua ao lado... }
6
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▹ Classe Square
public class Square { É necessária uma pen
externa para desenhar o
private Pen pen; quadrado na superfície
private Color color; associada
private Position position;
private int side;
// restante código
public void draw() {
pen.setColor(color);
pen.penUp();
pen.moveTo(position.getX(),position.getY());
pen.penDown();
Através dos pen.turnTo(0);
movimentos da pen
é possível efetuar o for(int i=0; i<4; i++) {
desenho duma figura pen.move(side);
pen.turn(90);
}
}
}
8
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▸ Classe Circle public class Circle {
private Pen pen;
private Color color;
private Position position;
private int radius;
Vários atributos
em comum com
a classe Square public Circle(Pen pen,Color color,Position position, int radius) {
this.pen = pen;
this.color = color;
this.position = position;
this.radius = radius;
}
// restante código
}
9
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▹ Classe Circle
public class Circle {
// restante código
public void draw() {
pen.setColor(color);
pen.penUp();
pen.moveTo(position.getX(),position.getY());
Estamos a
pen.penDown();
criar círculos pen.turnTo(0);
aproximados
int sides = 50;
por polígonos
int side = (int)(2*Math.PI*radius/sides);
regulares de
for(int i=0; i<sides+1; i++) {
50 lados.
pen.move(side);
pen.turn((int)(360.0/sides));
}
}
}
10
Exemplo – Desenho casa
▸ Solução 1 – Implementar classes para as figuras geométricas
▹ Classe Triangle public class Triangle {
private Pen pen;
private Color color;
private Position position
private int height, width;
Com atributos
// restante código
em comum com
void draw() {
as outras classes pen.penUp();
pen.moveTo(x, y);
pen.penDown();
pen.turnTo(0);
13
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
▹ Tipo FigureType
14
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
▹ Classe Figure - Construtores
public Figure(FigureType figureType, Pen pen, Color color,
Position position, int dimension) {
this.figureType = figureType;
if (figureType == FigureType.CIRCLE) {
circle = new circle(pen, color, position, dimension);
} else { Confuso!
square = new Square(pen, color, position, dimension);
}
}
public Figure(FigureType figureType, Pen pen, Color color,
Position position, int height, int width) {
this.figureType = figureType;
if (figureType == FigureType.TRIANGLE) {
triangle = new Triangulo(pen, color, position, height, width);
} else {
rectangle = new Retangulo(pen, color, position, height, width);
}
}
15
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
▹ Classe Figure - draw public void draw() {
switch(figureType) {
case CIRCLE:
Um switch para lidar circle.draw();
com os diferentes tipos break;
case TRIANGLE:
de figura
triangle.draw();
break;
case RECTANGLE:
rectangle.draw();
break;
Muitas vezes as instruções switch são pistas que
nos indicam que poderá existir um problema de case SQUARE:
coesão onde estão representadas várias square.draw();
entidades e em que a solução passa pela break;
herança (e polimorfismo)
}
}
16
Exemplo – Desenho casa
▸ Solução 1 – Implementar uma classe para representar figuras
public class Drawing {
▹ Classe Drawing private ArrayList<Figure> figures;
public Drawing() {
figures = new ArrayList<>();
}
drawing.addFigure(wall);
drawing.addFigure(window);
drawing.addFigure(roof);
drawing.addFigure(sun);
drawing.draw();
}
}
19
Exemplo – Desenho casa
20
Desenho Casa –
Solução 2
▸ Polimorfismo
21
Exemplo – Desenho Casa
▸ Requisitos do desenho (Revisitado):
▹ O desenho é composto por quadrados, triângulos, círculos e
retângulos.
▹ Cada uma das formas geométricas tem uma cor e uma
posição.
▹ O desenho reutiliza as classes Pen e Canvas do ambiente
gráfico. Neste caso as figuras são desenhadas apenas com
as linhas de contorno.
▹ Deverá ser possível criar facilmente outros desenhos com as
figuras geométricas existentes (circulo, quadrado, triângulo
e retângulo).
22
Exemplo – Desenho Casa
▸ Foram criadas 2 soluções:
▹ Solução 1:
▹ Classes para cada tipo de forma geométrica: Square, Rectangle,
Circle, Triangle.
▹ Um classe Figure que pode ser qualquer das figuras existentes.
▹ Uma classe Drawing para o desenho que guarda uma lista de figuras.
▹ Solução 2:
▹ Uma classe Figure que representa qualquer figura.
▹ Uma classe Drawing para o desenho que guarda uma lista de figuras.
23
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure
public class Figure { Tipo enumerado TipoFigura para
definir o tipo de figura guardado
private FigureType type;
private Pen pen;
private Position position;
private Color color;
private int height; Atributos
private int width;
necessários para
private int radius;
os vários tipos de
figura que poderão
// restante código
}
ser utilizados
24
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Tipo FigureType
25
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - Construtor
26
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - setCircle e setSquare
pen.penUp();
pen.moveTo(position.getX(), position.getY());
pen.setColor(color);
pen.penDown();
// continua…
29
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - draw
switch (type) {
case CIRCLE:
drawCircle();
break;
case TRIANGLE:
drawTriangle();
break;
case RECTANGLE:
drawRectangle();
break;
case SQUARE:
drawSquare();
break;
}
}
30
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - drawSquare e drawCircle
private void drawSquare() {
for (int i = 0; i < 4; i++) {
pen.move(width);
pen.turn(90);
}
}
private void drawCircle() {
int sides = 50;
int side = (int) (2 * Math.PI * radius / sides);
32
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Figure - drawTriangle
33
Exemplo – Desenho casa
▸ Solução 2 – Implementar uma classe para representar figuras
▹ Classe Drawing public class Drawing {
private ArrayList<Figure> figures;
public Drawing() {
figures = new ArrayList<>();
}
35
Exemplo – Desenho casa
▸ Solução 2 – Programa principal
▹ Ex: representar o desenho da casa
drawing.draw();
}
36
Exemplo – Desenho casa
37
Desenho Casa:
Herança e Polimorfismo
▸ Polimorfismo
38
Exemplo – Desenho Casa
▸ Problemas das soluções apresentadas:
▹ Solução 1
▹ Código duplicado nas várias formas geométricas
▹ Classe Figure com um atributo por cada tipo de forma geométrica
▹ Solução 2
▹ Classe Figure complexa
▹ Classe Figure com problemas de coesão ao representar as várias
formas geométricas
39
Exemplo – Desenho Casa
▸ Solução com herança de classes e polimorfismo:
▹ Criar uma superclasse Figure com os atributos comuns das formas
geométricas
▹ Criar sublasses para cada uma das formas geométricas.
▹ Criar uma classe Drawing que irá guardar uma lista de formas
geométricas tirando partido do Principio da Substituição
▹ Método draw da classe Figure polimórfico.
▹ O resultado da sua execução depende da figura que estiver na lista.
40
Exemplo – Desenho Casa
▸ Classes da solução 1: public class Rectangle {
public class Square {
private Pen pen;
private Pen pen; private Color color;
private Color color; private Position position;
private Position position; private int height, width;
private int side;
// restante código
// restante código Vários atributos
em comum }
}
Construtor sem
public Figure() {
argumentos
pen = new Pen();
position = new Position();
color = Color.BLACK;
}
// restante código
}
42
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure(Position position,
public Figure() {
Pen pen, Color color) {
pen = new Pen();
if (pen != null) {
position = new Position();
this.pen = pen;
color = Color.BLACK;
} else {
}
this.pen = new Pen();
}
public Figure(Pen pen, Color color) {
if (position != null) {
if (pen != null) {
this.position =
this.pen = pen;
new Position(position.getX(),
} else {
position.getY());
this.pen = new Pen();
} else {
}
this.position = new Position();
position = new Position();
}
if (color != null) {
if (color != null) {
this.color = color;
this.color = color;
} else {
this.color = Color.BLACK; Aqui também existe } else {
this.color = Color.BLACK;
} alguma duplicação
}
} de código }
43
Construtores – this()
public class Clock {
▸ this() nos construtores
private int hours;
▹ Da mesma maneira que se utiliza private int minutes;
private int seconds;
super() para a chamada ao Chamada ao construtor:
public Clock(){ Clock(int hours, int
construtor da classe base é this(0,0,0); minutes, int seconds)
}
possível usar this() para a
public Clock(int hours, int minutes){
chamada doutro construtor da this(hours, minutes, 0);
própria classe. }
44
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure(Position position,
Pen pen, Color color) {
if (pen != null) {
this.pen = pen;
public Figure() { } else {
this(new Position(), new Pen(), Color.BLACK); this.pen = new Pen();
} }
if (position != null) {
this.position =
public Figure(Pen pen, Color color) {
new Position(position.getX(),
this(new Position(), pen, color); position.getY());
} } else {
this. position = new Position();
}
if (color != null) {
this.color = color;
Assim evita-se a } else {
duplicação de código nos
this.color = Color.BLACK;
construtores }
} 45
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure(Position position,
Pen pen, Color color) {
public Figure() { if (pen != null) {
this(new Position(), new Pen(), Color.BLACK); this.pen = pen;
} } else {
this.pen = new Pen();
}
public Figure(Pen pen, Color color) {
if (position != null) {
this(new Position(), pen, color); this.position =
} new Position(position.getX(),
position.getY());
} else {
this. position = new Position();
}
Outra simplificação que
if (color != null) {
pode ser feita é a utilização this.color = color;
do operador ternário em } else {
substituição dos if this.color = Color.BLACK;
}
} 46
Operador ternário
▸ Operador ternário – ?!
String period;
if (hours < 12) {
Ø Equivalente com ifs: period = "am";
} else {
period = "pm";
}
47
Exemplo – Desenho Casa
▸ Solução 3 – classe base Figure – construtores
public Figure() {
this(new Position(), new Pen(), Color.BLACK);
}
48
Exemplo – Desenho Casa
▸ Solução 3 – classe derivada Circle
public class Circle extends Figure {
public Circle() {
this.radius = 1;
}
// restante código
} 49
Exemplo – Desenho Casa
@Override
▸ Solução 3 – classe public void draw() {
derivada Circle: Pen pen = getPen();
pen.setColor(getColor());
método draw pen.penUp();
pen.moveTo(getX(),getY());
pen.penDown();
pen.turnTo(0);
50
Exemplo – Desenho Casa
▸ Solução 3 – classe public class Square extends Figure {
public Square() {
this.side = 1;
}
// restante código
}
51
Exemplo – Desenho Casa
@Override
▸ Solução 3 – classe derivada public void draw() {
52
Exemplo – Desenho casa
public class Drawing {
idêntica.
public void draw() {
for (Figure figure : figures) {
figure.draw();
}
}
}
53
Exemplo – Desenho casa
public class Drawing {
▹ Classe Drawing }
figures = new ArrayList<>();
drawing.addFigure(wall);
drawing.addFigure(window);
drawing.addFigure(roof);
drawing.addFigure(sun);
Código idêntico
drawing.draw();
ao da solução 1
}
} 56
Exemplo – Desenho casa
▸ Solução 3 – Diagrama de classes
57
Programação Orientada por Objetos
Classes
Abstratas e
Interfaces
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
2
Classes Abstratas e Interfaces
3
Exemplo – Foxes and Rabbits
▸ Requisitos da aplicação:
▹ Um simulador da evolução de populações de raposas e coelhos num campo
limitado.
▹ Na simulação os coelhos andam livremente pelo campo enquanto as raposas os
caçam.
▹ O equilíbrio das populações é obtido da seguinte forma:
▹ Quando existem muitos coelhos não falta alimento às raposas e a sua população
cresce rapidamente.
▹ Com muitas raposas a caçar a população de coelhos começa a diminuir levando à
diminuição do alimento das raposas e consequentemente à redução da sua
população.
▹ Com poucas raposas a população de coelhos começa a crescer e o ciclo repete-se
4
Exemplo – Foxes and Rabbits
▸ Simulação:
5
Exemplo – Foxes and Rabbits
▸ Diagrama de classes
da aplicação Foxes
and Rabbits:
6
Exemplo – Foxes and Rabbits
7
Exemplo – Foxes and Rabbits
8
Classes Abstratas e Interfaces
Código da aplicação
9
Exemplo – Foxes and Rabbits
▸ Diagrama de classes da aplicação Foxes and Rabbits:
10
Exemplo – Foxes and Rabbits
Idade mínima de reprodução
▸ Classe Rabbit public class Rabbit {
// continua…
11
Exemplo – Foxes and Rabbits
public Rabbit(boolean randomAge, Field field, Location location) {
▸ Classe Rabbit – age = 0;
alive = true;
construtor e método run this.field = field;
Ação principal dos coelhos:
setLocation(location);
if(randomAge) { executada a cada passo da
age = rand.nextInt(MAX_AGE); simulação para cada coelho
}
}
12
Exemplo – Foxes and Rabbits
public void run(List<Rabbit> newRabbits) {
incrementAge();
▸ Classe Rabbit – método run if(alive) {
giveBirth(newRabbits);
Location newLocation = field.freeAdjacentLocation(location);
if(newLocation != null) {
setLocation(newLocation);
}
else {
setDead();
}
}
}
14
Exemplo – Foxes and Rabbits
private void incrementAge() {
age++;
▸ Classe Rabbit – métodos if(age > MAX_AGE) {
incrementAge e setDead();
}
giveBirth }
15
Exemplo – Foxes and Rabbits
private int breed() {
▸ Classe Rabbit – métodos breed, e int births = 0;
canBreed if(canBreed() && rand.nextDouble() <= BREEDING_PROBABILITY) {
births = rand.nextInt(MAX_LITTER_SIZE) + 1;
}
return births;
}
16
Exemplo – Foxes and Rabbits
Idade mínima de reprodução
public class Fox {
17
Exemplo – Foxes and Rabbits
public Fox(boolean randomAge, Field field, Location location) {
▸ Classe Fox – construtor age = 0;
alive = true;
this.field = field;
setLocation(location);
if(randomAge) {
age = rand.nextInt(MAX_AGE);
foodLevel = rand.nextInt(RABBIT_FOOD_VALUE);
}
else {
foodLevel = rand.nextInt(RABBIT_FOOD_VALUE);
}
}
18
Exemplo – Foxes and Rabbits
public void hunt(List<Fox> newFoxes) {
incrementAge(); A lista newFoxes recebida é
incrementHunger(); preenchida com as raposas que
if(alive) { nasceram
giveBirth(newFoxes);
19
Exemplo – Foxes and Rabbits
public void hunt(List<Fox> newFoxes) {
incrementAge();
incrementHunger();
if(alive) {
giveBirth(newFoxes);
Location newLocation = findFood();
21
Exemplo – Foxes and Rabbits
▸ Classe Fox – métodos isAlive, public boolean isAlive() {
return alive;
}
22
Exemplo – Foxes and Rabbits
private void incrementAge() {
23
Exemplo – Foxes and Rabbits
24
Exemplo – Foxes and Rabbits
▸ Classe Simulator
public class Simulator {
// continua…
25
Exemplo – Foxes and Rabbits
▸ Classe Simulator – public Simulator() {
this(DEFAULT_DEPTH, DEFAULT_WIDTH); Utiliza this() para evitar a
} duplicação de código nos
construtores public Simulator(int depth, int width) {
contrutores
if(width <= 0 || depth <= 0) {
System.out.println("The dimensions must be greater than zero.");
System.out.println("Using default values.");
depth = DEFAULT_DEPTH;
width = DEFAULT_WIDTH;
}
reset();
}
26
Exemplo – Foxes and Rabbits
▸
public void reset() {
Classe Simulator – métodos step = 0;
rabbits.clear();
reset e populate foxes.clear();
populate();
view.showStatus(step, field);
}
}
}
}
27
public void simulateOneStep() {
Exemplo – step++;
Rabbits
Rabbit rabbit = it.next();
rabbit.run(newRabbits);
if(! rabbit.isAlive()) {
it.remove();
}
▸
}
Classe Simulator – List<Fox> newFoxes = new ArrayList<Fox>();
método for(Iterator<Fox> it = foxes.iterator(); it.hasNext(); ) {
Fox fox = it.next();
simulateOneStep fox.hunt(newFoxes);
if(! fox.isAlive()) {
it.remove();
}
}
rabbits.addAll(newRabbits);
Passo da simulação: foxes.addAll(newFoxes);
onde se executam as
view.showStatus(step, field);
ações principais
}
28
▸ Classes Abstratas e Interfaces
Classes e Métodos
Abstratos
29
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação:
▹ Mais uma vez existem classes com vários atributos e métodos idênticos
onde se pode aplicar a herança. É o caso das classes Fox e Rabbit
▹ Criação da superclasse Animal com os atributos e métodos comuns que fizerem sentido.
▹ Na simulação temos listas separadas para raposas e coelhos, com a
herança e usando o principio da substituição podemos ter apenas uma lista
de Animal
▹ A cada passo da simulação as raposas caçam e os coelhos correm. Neste
caso poderíamos tirar partido do polimorfismo onde cada um deles faz a sua
ação.
30
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação: criação da classe Animal
public class Rabbit {
public class Fox {
private static final int BREEDING_AGE = 5;
private static final int BREEDING_AGE = 15; private static final int MAX_AGE = 40;
private static final int MAX_AGE = 150; private static final double BREEDING_PROBABILITY = 0.12;
private static final double BREEDING_PROBABILITY = 0.08; private static final int MAX_LITTER_SIZE = 4;
private static final int MAX_LITTER_SIZE = 2; Vários atributos
private static final int RABBIT_FOOD_VALUE = 9; idênticos
private static final Random rand =
private static final Random rand = Randomizer.getRandom(); Randomizer.getRandom();
private static final int BREEDING_AGE = 15; private static final int BREEDING_AGE = 5;
private static final int MAX_AGE = 150; private static final int MAX_AGE = 40;
private static final double BREEDING_PROBABILITY = 0.08; private static final double BREEDING_PROBABILITY = 0.12;
private static final int MAX_LITTER_SIZE = 2; private static final int MAX_LITTER_SIZE = 4;
private static final int RABBIT_FOOD_VALUE = 9;
private static final Random rand = private static final Random rand =
Randomizer.getRandom(); Randomizer.getRandom();
Ø Os métodos seletores e modificadores associados aos atributos alive, location e field passam também para a classe Animal
Ø Vai ser necessário acrescentar um método getField na classe Animal porque esse atributo é acedido dentro de outros
métodos das classes Fox e Rabbit 32
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação: criação da classe Animal
public class Fox { public class Rabbit {
Ø A visibilidade do método setLocation é private, se se quiser ter acesso a este método nas subclasses tem de se alterar para
protected pelo menos na classe Animal.
Ø O método setDead é public na classe Rabbit e private na classe Fox porque na classe Fox era necessário aceder a esse método
da classe Rabbit. Neste caso pode-se passar também a protected tendo em conta que não se pretende que o método faça parte da
interface da classe
33
Exemplo – Foxes and Rabbits
▸ Análise e alterações à public class Simulator {
// continua…
private List<Animal> animals;
34
Exemplo – Foxes and Rabbits
public class Simulator {
public void simulateOneStep() {
▸ Análise e alterações à // código omitido
for(Iterator<Animal> it = animals.iterator(); it.hasNext(); )
aplicação: classe {
Animal animal = it.next();
Simulator if(animal instanceOf Rabbit) {
Rabbit rabbit = (Rabbit) animal;
rabbit.run(newAnimals);
}
else if(animal instanceOf Fox) { É necessário identificar o tipo
Fox fox = (Fox) animal; de animal com instanceOf
fox.hunt(newFoxes);
}
else {
System.out.println("found unknown animal");
}
if(!animal.isAlive()) {
it.remove();
}
}
Ø Solução: criar o método act na classe Animal que na classe Fox chama o método hunt e na classe Rabbit
chama o método run.
Ø Neste caso volta a acontecer o problema: “que código colocar no método act da classe Animal”?
Ø Na realidade a classe Animal é abstrata, não existem “animais” em abstrato mas sim instâncias particulares de animais
como é o caso da raposa ou do coelho.
36
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação:
public class Simulator {
public void simulateOneStep() {
// código omitido
classe Simulator
for(Iterator<Animal> it = animals.iterator(); it.hasNext(); )
{
Animal animal = it.next();
animal.act(newAnimals);
if(! animal.isAlive()) {
it.remove();
}
}
Ø Quando se tem um método para o qual não se pretende definir o código dizemos que é um método abstrato
Ø Em Java é possível criar um método abstrato
37
Métodos abstratos
▸ Métodos abstratos em Java
modificador abstract sem código e a terminar em ;
38
Classes abstratas
▸ Classes abstratas em Java
modificador abstract
39
Classes e métodos abstratos
▸ Regras das classes e métodos abstratos:
▹ Um método abstrato não tem código
▹ Uma classe abstrata não tem instâncias
▹ Se uma classe tiver pelo menos um método abstrato ela terá de ser obrigatoriamente abstrata
▹ Caso contrário existirá um erro de compilação
▸ As classes abstratas são usadas para:
▹ Definir uma classe base da qual não se pretende criar objetos
▹ Definir uma classe incompleta que inclui um conjunto de métodos (concretos) que servem de base à implementação de
classes semelhantes.
▹ Neste caso criam-se métodos abstratos que devem ser definidos nas classes derivadas e assim concluir a
construção da classe desse tipo
▸ Os métodos abstratos criados numa classe são herdados pelas classes derivadas.
▹ Neste caso devem ser redefinidos nas classes derivadas
▹ Se não forem definidos numa classe derivada essa classe passa a ter um método abstrato e
consequentemente deve ser obrigatoriamente abstrata.
41
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação: novo método act public class Fox extends Animal {
// código omitido
42
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação: criação da classe Animal
public class Fox { public class Rabbit {
// continua… // continua…
Ø Alguns métodos não foram colocados na classe Animal porque dependiam de constantes diferentes nas classes
derivadas, é o caso, por exemplo do método canBreed
Ø Neste caso as constantes (e os atributos), ao contrário dos métodos não podem ser redefinidos nas classes derivadas pelo
que não faz sentido serem colocadas na classe base.
Ø Com os métodos abstratos e o polimorfismo pode-se alterar a situação…
43
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação: método canBreed public class Fox extends Animal {
// código omitido
private static final int BREEDING_AGE = 15;
método getBreedingAge abstrato @Override
protected int getBreedingAge() {
return BREEDING_AGE;
public abstract class Animal { }
}
// código omitido
private int age;
métodos getBreedingAge redefinidos nas subclasses
private boolean canBreed() {
return age >= getBreedingAge();
} public class Rabbit extends Animal {
private static final int BREEDING_AGE = 5;
protected abstract int getBreedingAge();
} @Override
protected int getBreedingAge() {
return BREEDING_AGE;
}
Polimorfismo do método getBreedingAge a funcionar }
44
Classes Abstratas e Interfaces
Interfaces
45
Exemplo – Foxes and Rabbits
▸ Novas funcionalidades da simulação:
▹ Uma nova funcionalidade poderá ser a adição de mais animais.
▹ Simples de implementar criando uma nova subclasses da classe Animal.
▹ Outra funcionalidade seria a inclusão de predadores humanos.
▹ Podiam ser, por exemplo, caçadores ou apenas colocarem armadilhas
▹ Neste caso os atores da simulação não seriam apenas animais.
▹ Outros atores a incluir podiam ser plantas ou mesmo as condições meteorológicas.
▹ As plantas influenciariam a população de coelhos e o crescimento das plantas seria
influenciado pelas condições atmosféricas
▹ Nos casos anteriores temos novos atores na simulação mais gerais. Uma solução para poder
continuar a tirar partido do polimorfismo do método act seria a criação de uma classe Actor que
servisse de base às classes referidas e que incluísse o método referido como abstrato.
46
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação: novas classes Actor e Hunter
47
Exemplo – Foxes and Rabbits
▸ Análise e alterações à aplicação: nova classe Actor e Hunter
Ø Neste caso a classe Actor poderia ser simplesmente:
Mas uma classe que apenas tem métodos abstratos pode ser
definida usando um novo tipo de dados em Java: as interfaces
48
Interfaces
Palavra reservada interface
Lista de métodos
▸ Interfaces em Java
public interface Actor {
void act(List<Actor> newActors);
boolean isActive();
}
Ø As classes podem herdar das interfaces da mesma forma que herdam duma classe.
Ø Neste caso usam a palavra implements em vez de extends
Ø Diz-se que uma classe implementa uma interface porque, neste caso, ela terá de implementar todos
os seus métodos. Caso contrário passará a ser uma classe abstrata.
50
Interfaces
▸ Interfaces em Java
Ø As classes que implementam várias interfaces na prática terão de implementar todos os métodos
que existem nessas interfaces.
51
Interfaces
▸ As interfaces definem um novo tipo de dados
▹ Apesar de ser possível criar variáveis do tipo interface não é possível criar valores do tipo interface.
▹ Neste caso uma variável deste tipo apenas pode guardar um objeto duma classe que
implementa essa interface. Uma classe que implementa uma interface é um subtipo dessa
interface.
Exemplo: Actor actor = new Fox();
▹ O polimorfismo está disponível para interfaces da mesma forma que está para classes
52
Interfaces
▸ As interfaces são especificações de comportamentos
▹ Separam as funcionalidades (os seus métodos abstratos) da sua implementação (nas classes que as implementam)
▹ As classes que implementa essas especificações podem escolher a forma de o fazer.
54
Classes abstratas e Interfaces
▸Classes abstratas Ø Interfaces
56
Programação Orientada por Objetos
Classes
Abstratas e
Interfaces
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
2
Exemplo raposas e
coelhos – Melhorias no
código
▸ Classes Abstratas e Interfaces
3
Exemplo – Foxes and Rabbits
4
Exemplo – Foxes and Rabbits
▸ Diagrama de classes da
aplicação Foxes and Rabbits:
5
Exemplo – Foxes and Rabbits
▸ Diagrama de classes da aplicação Foxes and Rabbits:
Pelo diagrama de
classes vê-se que existe
uma dependência entre
a classe Simulator e as
classes Rabbit e Fox
6
Exemplo – Foxes and Rabbits
public class Simulator {
private static final int DEFAULT_WIDTH = 120;
▸ Classe Simulator private static final
private static final
int DEFAULT_DEPTH = 80;
double FOX_CREATION_PROBABILITY = 0.02;
private static final double RABBIT_CREATION_PROBABILITY = 0.08;
7
Exemplo – Foxes and Rabbits
▸ Classe Simulator
// Continuação da classe Simulator
public void reset() {
step = 0;
animals.clear();
populate();
Para (re)iniciar a
simulação. Não tem as view.showStatus(step, field);
dependências }
encontradas
private void populate() {
Random rand = Randomizer.getRandom();
field.clear();
for(int row = 0; row < field.getDepth(); row++) {
Para criar e distribuir a for(int col = 0; col < field.getWidth(); col++) {
população inicial de if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
raposas e coelhos Location location = new Location(row, col);
Fox fox = new Fox(true, field, location);
animals.add(fox);
}
else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Aqui estão as Rabbit rabbit = new Rabbit(true, field, location);
animals.add(rabbit);
dependências às }
classes Rabbit e Fox // else leave the location empty.
}
}
}
8
Exemplo – Foxes and Rabbits
▸ Classe Simulator (Dependências)
public class Simulator {
// Código omitido
private static final double FOX_CREATION_PROBABILITY = 0.02;
private static final double RABBIT_CREATION_PROBABILITY = 0.08;
12
Exemplo – Foxes and Rabbits
▸ Diagrama de classes da aplicação Foxes and Rabbits:
Sem dependências
a Rabbit e/ou a Fox
Nova classe
PopulationGenerator
13
Exemplo – Foxes and Rabbits
▸ Continuação da análise às Classes Fox e Rabbit
public class Rabbit {
public class Fox {
// código omitido
// código omitido
private void giveBirth(List<Animal> newRabbits) {
private void giveBirth(List<Animal> newFoxes) {
Field field = getField();
Field field = getField(); List<Location> free =
List<Location> free =
field.getFreeAdjacentLocations(getLocation()); field.getFreeAdjacentLocations(getLocation());
int births = breed(); int births = breed();
for(int b=0; b<births && free.size() > 0; b++) { for(int b=0; b<births && free.size() > 0; b++) {
Location loc = free.remove(0); Código Location loc = free.remove(0);
Fox young = new Fox(false, field, loc);
newFoxes.add(young); parecido Rabbit young = new Rabbit(false, field, loc);
newRabbits.add(young);
} }
} }
// continua… // continua…
Ø Embora o código dos métodos seja diferente é possível passa-los para a classe Animal
tirando partido do polimorfismo.
14
Exemplo – Foxes and Rabbits
Novos métodos abstratos
▸ Nova classe Animal public abstract class Animal {
} O método createAnimal retorna um objeto Rabbit embora o tipo de retorno seja Animal.
Isto é possível pelo princípio da substituição
16
Exemplo raposas e coelhos
– Nova Funcionalidade
17
Exemplo – Foxes and Rabbits
▸ Acrescentar a nova classe Hunter
Ø Neste caso vai introduzir-se a interface Actor como foi sugerido anteriormente
21
Exemplo – Foxes and Rabbits
// continuação da classe Hunter…
▸ Nova classe Hunter
public void act(List<Actor> newActors) {
int kills = 0;
List<Location> adjacent = field.adjacentLocations(location);
Iterator<Location> it = adjacent.iterator();
22
Exemplo – Foxes and Rabbits
public class PopulationGenerator {
private static final double HUNTER_CREATION_PROBABILITY = 0.01; ▸ Nova classe PopulationGenerator
// outras constantes omitidas
public PopulationGenerator(SimulatorView view) {
view.setColor(Hunter.class, Color.red);
// código omitido
} Os caçadores ficam
public void populate(Field field, List<Actor> actors) { com a cor vermelha na
Random rand = Randomizer.getRandom();
for(int row = 0; row < field.getDepth(); row++) {
nova simulação
for(int col = 0; col < field.getWidth(); col++) {
if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Animal fox = new Fox(true, field, location);
actors.add(fox);
}
else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Animal rabbit = new Rabbit(true, field, location);
actors.add(rabbit);
}
else if(rand.nextDouble() <= HUNTER_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Hunter hunter = new Hunter(field, location);
actors.add(hunter);
}
}
}
}
}
23
Exemplo – Foxes and Rabbits
▸ Diagrama de classes da nova versão da aplicação
24
Exemplo – Foxes and Rabbits
▸ Visualização da nova versão da aplicação
25
Desenho Casa –
Melhorias e Nova
Funcionalidade
▸ Classes Abstratas e Interfaces
26
Exemplo – Desenho Casa
27
Exemplo – Desenho casa
▸ Diagrama de classes da
solução existente
28
Exemplo – Desenho Casa
▸ Classes relacionadas com figuras geométricas da solução existente:
public class Square extends Figure {
public class Figure {
private int side;
private Pen pen;
private Position position; // restante código
private Color color; }
// restante código
} 29
Exemplo – Desenho casa
public class Drawing { ▸ Solução existente – classe Drawing
private ArrayList<Figure> figures;
public Drawing() {
figures = new ArrayList<>();
}
public Figure() {
this(new Position(), new Pen(), Color.BLACK);
}
32
Exemplo – Desenho casa
▸ Diagrama de classes da solução
Representação
de uma classe
abstrata
33
Exemplo – Desenho casa
34
Exemplo – Desenho Casa
public class Person {
▸ Classe Person
private int height;
private int width;
private Position position; Utiliza a pen
private Color color;
private Pen pen; para o desenho
public Person() {
this(new Pen());
}
// restante código
}
35
Exemplo – Desenho Casa
▸ Classe Person - método draw
public void draw() {
int bh = (int) (height * 0.7);
int hh = (height - bh) / 2;
int hw = width / 2;
int x = position.getX();
int y = position.getY();
int[] xpoints = {x - 3, x - hw, x - hw, x - (int) (hw * 0.2) - 1, x - (int) (hw * 0.2) - 1, x - hw,
x - hw + (int) (hw * 0.4) + 1, x, x + hw - (int) (hw * 0.4) - 1, x + hw, x + (int) (hw * 0.2) + 1,
x + (int) (hw * 0.2) + 1, x + hw, x + hw, x + 3, x + (int) (hw * 0.6),
x + (int) (hw * 0.6), x + 3, x - 3, x - (int) (hw * 0.6), x - (int) (hw * 0.6)};
int[] ypoints = {y, y + (int) (bh * 0.2), y + (int) (bh * 0.4), y + (int) (bh * 0.2),
y + (int) (bh * 0.5), y + bh, y + bh, y + (int) (bh * 0.65), y + bh, y + bh,
y + (int) (bh * 0.5), y + (int) (bh * 0.2), y + (int) (bh * 0.4), y + (int) (bh * 0.2),
y, y - hh + 3, y - hh - 3, y - hh - hh, y - hh - hh, y - hh - 3, y - hh + 3};
pen.penUp();
pen.moveTo(xpoints[0], ypoints[0]);
pen.penDown(); Pontos de um
polígono com o
for (int i = 1; i < xpoints.length; i++) {
pen.moveTo(xpoints[i], ypoints[i]);
contorno da pessoa
}
pen.moveTo(xpoints[0], ypoints[0]);
}
36
Exemplo – Desenho Casa
public void setSize(int height, int width) {
39
Exemplo – Desenho Casa
Solução
▸ Solução 1:
▹ Criar uma classe base GraphicElement e fazer as classes Figure e
Person herdarem desta classe. O desenho passaria a ser uma lista de
elementos gráficos.
▹ Poderia ser uma boa solução se quiséssemos apenas utilizar a classe
Person apenas para os desenhos.
▸ Solução 2
▹ Criar uma interface Drawable com o método draw e implementar esta
interface nas classes Figure e Person.
▹ Vamos optar por esta solução.
40
Exemplo – Novo Desenho Casa
▸ Interface Drawable
41
Exemplo – Novo Desenho Casa
▸ Classe Person public class Person implements Drawable {
@Override
public void draw() {
// código omitido
}
Tem que implementar o
método draw da interface
// restante código Drawable
}
42
Exemplo – Novo Desenho Casa
▸ Classe base Figure
public abstract class Figure implements Drawable {
Ø Como o método draw não é implementado a classe fica com o método da interface que é abstrato,
torna-se abstrata porque não o implementa e deixa para as classes derivadas a sua implementação.
43
Exemplo – Novo Desenho Casa
public class Drawing {
▸ Nova classe Drawing
private ArrayList<Drawable> figures;
45
Exemplo – Novo Desenho Casa
▸ método main
public static void main() {
drawing.addFigure(wall);
drawing.addFigure(window);
drawing.addFigure(roof);
drawing.addFigure(sun);
drawing.addFigure(person);
drawing.draw();
}
46
Exemplo – Novo Desenho Casa
▸ Diagrama de classes do novo desenho casa
Representação
da interface
47
Bibliografia
48
Programação Orientada por Objetos
Coleções do
Java
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Coleções e Listas
▸ Conjuntos
▸ Mapas
▸ Exemplo Escola, Algoritmos
2
Coleções e Listas
▸ Coleções
Coleções e a Java Collections Framework
▸ Coleções: permitem agrupar vários elementos
▸ Java Collections Framework (JCF):
▹ É uma arquitetura unificada que inclui interfaces, classes (abstratas e concretas) e
algoritmos (implementados por métodos).
▹ A JCF inclui quatro tipos principais de coleções:
▹ Conjuntos (Set): Coleção de elementos sem ordem e sem elementos repetidos
▹ Listas (List): Coleção de elementos ordenados e com possíveis repetições
▹ Mapas (Map): Coleção de pares chave-valor, sem repetição da chave
▹ Filas (Queue) : Sequências de elementos com diferentes critérios de inserção e remoção
4
Breve introdução às Interfaces em Java
▸ Como uma classe, uma interface pode ter métodos e variáveis, mas os métodos
declarados numa interface são abstratas por defeito (incluem apenas a assinatura
de método, sem corpo).
▸ As interfaces especificam o que uma classe deve fazer e não como.
▹ É o papel da classe implementar o método.
▸ Uma Interface é sobre funcionalidades como um jogador (Player) pode ser uma
interface e qualquer classe que implemente Player deve ser capaz de (ou deve
implementar) o método move().
▸ Portanto, a interface especifica um conjunto de métodos que a classe deve
implementar.
5
Interfaces em Java
▸ Se uma classe implementa uma interface e não fornece corpos de método para
▹ Se uma classe implementa essa interface, ela pode ser usada para ordenar
uma coleção.
6
Sintaxe interface <nome_da_interface> {
// declare as constantes
// declare os métodos que são abstratos
// por defeito.
}
Exemplo
int speed;
int gear;
gear = newGear;
}
interface Vehicle {
// para acelerar
@Override
// all are the abstract methods. public void speedUp(int increment){
public void changeGear(int a);
speed = speed + increment;
public void speedUp(int a); }
public void applyBrakes(int a);
} // para decelerar
@Override
public void applyBrakes(int decrement){
8
Java Collections Framework – Interfaces Genéricas
▸ As coleções da JCF são definidas através de interfaces. Neste caso cada uma das interfaces
estabelece os métodos que um determinado tipo de coleção deve ter.
9
Java Collections Framework – Interfaces, classes abstratas e classes
10
Java Collections Framework – Interfaces Genéricas
A JCF define interfaces genéricas permitindo que se possa utilizar nas coleções um determinado tipo de
dados escolhido pelo programador.
▸ Exemplos:
▹ public interface Collection<E> …
▹ Coleção de elementos do tipo ‘E’lement
▹ public interface Map<K,V> …
▹ Mapa de elementos do tipo ‘V’alue com chave do tipo ‘K’ey.
11
Coleções – Interface Collection<E>
12
Coleções – Interface List<E>
▸ List<E> para coleções com elementos em
sequência.
▹ Os elementos nas listas estão ordenados
▹ As listas podem ter elementos duplicados.
▹ O cliente de uma Lista tem, normalmente, controlo
sobre a posição onde um elemento é inserido.
▹ O acesso a um elemento é feito por um índice
(referência de posição).
13
Coleções – ArrayList<E>
▸ ArrayList<E> – é a implementação da interface List<E> mais comum e que possui um bom
desempenho especialmente no acesso aos dados e nas operações de iteração.
▹ A implementação interna utiliza arrays.
▹ ArrayList<Person> persons = new ArrayList<>();
▹ Declara e cria um ArrayList chamado persons para armazenar objetos da classe Person
▸ A JCF define as coleções através de interfaces e disponibiliza várias classes que implementam
essas coleções.
▹ Neste caso a classe genérica ArrayList<E> é uma das implementações disponíveis na
JCF para a interface List<E>
14
Exemplo – Utilização de listas
15
Coleções – ArrayList<E>
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("IPOO");
list.add("POO");
▸ Exemplo de utilização: list.add("POO");
list.add("IPOO");
for(int i = 0; i <list.size(); ++i) {
if (list.get(i).equals("POO")) {
list.remove(i);
}
}
list.remove("IPOO");
for(int i = 0; i <list.size(); ++i) {
System.out.println(list.get(i));
}
}
16
Coleções – LinkedList<E>
▸ LinkedList<E> – É outra implementação da interface List<E>. Nas operações de
inserção e remoção de elementos pode oferecer melhor desempenho do que a anterior.
▸ Internamente esta implementação não utiliza arrays, para não "desperdiçar" espaço, mas
regista, para cada elemento qual o próximo elemento e qual o elemento anterior, sendo então
fácil percorrer a lista e inserir e/ou remover elementos.
17
Exemplo – Utilização de listas
18
Coleções – LinkedList<E>
▸ Exemplo de utilização: public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
for (int val = 0; val < 10; val++) {
list.add(new Integer(val));
}
for (int i = 0; i < list.size(); i++) {
if (list.get(i).intValue() == 5) {
list.remove(i);
}
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
19
Coleções – Interface Iterator<E>
▸ A Interface Iterator<E> define os métodos essenciais para iterar (percorrer) uma coleção:
▹ hasNext() – Determinar se a coleção tem ou não um elemento seguinte.
▹ next() – Devolve o elemento seguinte da iteração
▹ remove() – Remove o último elemento iterado.
v Exemplo:
Iterator<Person> s1 = persons.iterator();
Ø Neste exemplo s1 vai guardar um objeto de uma classe que desconhecemos Iterator<E>. O objeto é obtido através da
chamada ao método iterator() que existe em todas as coleções (está declarado na interface Collection<E>)
Ø Através de s1 vai ser possível “iterar” (percorrer) a lista de pessoas.
Ø O método remove() vai permitir remover o elemento obtido com next() e é a única forma segura de alterar uma coleção
durante uma iteração.
20
Coleções – Interface Iterator<E>
public static void main(String[] args) {
Definimos stringList a partir da List<String> stringList = new ArrayList<>();
interface List<E>, assim podemos
System.out.println("Com while:");
mais tarde escolher outra stringList = fillList(stringList);
implementação Iterator<String> s1 = stringList.iterator();
▸ Exemplo: while (s1.hasNext()) {
System.out.println(s1.next());
s1.remove();
}
System.out.println("\nCom do-while:");
Vamos preencher a stringList = fillList(stringList);
lista num método Iterator<String> s2 = stringList.iterator();
separado if (s2.hasNext()) {
do {
System.out.println(s2.next());
s2.remove();
} while (s2.hasNext());
}
// Continua…
Iteração dos elementos da lista
21
System.out.println("\nCom for:");
stringList = fillList(stringList);
22
public static void main(String[] args) {
List<String> listaStrings = new ArrayList<>();
Coleções – Interface
System.out.println("Com while:");
listaStrings = preencherLista(listaStrings);
Iterator<E>
Iterator<String> s1 = listaStrings.iterator();
while (s1.hasNext()) {
System.out.println(s1.next());
s1.remove();
System.out.println("Com do-while:");
listaStrings = preencherLista(listaStrings);
Iterator<String> s2 = listaStrings.iterator();
if (s2.hasNext()) {
do {
System.out.println(s2.next());
s2.remove();
} while (s2.hasNext());
System.out.println("Com for:");
listaStrings = preencherLista(listaStrings);
Iterator<String> s3 = listaStrings.iterator();
for (int i = 0; i < listaStrings.size(); i++) {
if (s3.hasNext()) {
System.out.println(s3.next());
s3.remove();
}
}
} 23
Conjuntos
▸ Coleções
24
Coleções – Interface Set<E>
25
Coleções – Classes que implementam
Set<E>
▸ HashSet<E> – armazena os elementos numa hash table.
▹ É a implementação com melhor desempenho mas não garante nada quanto à ordem de
iteração.
▹ HashSet<Person> persons = new HashSet<>();
▹ Declara e cria um HashSet chamado persons para armazenar objetos da classe Person.
▸ Assim a melhor forma para percorrer os elementos de um conjunto é através do ciclo for aprimorado ou
de um iterator
▸ Tal como com as outras coleções devemos declarar a variável com a interface Set e depois escolher a
implementação desejada (HashSet, TreeSet, LinkedHashSet). Assim minimiza-se o
“Acoplamento de Subclasses”:
Coleções - Classe
teachers.add("Ana");
teachers.add("Joao");
HashSet<E>
for (String s : teachers) {
System.out.println(s);
}
students.add("Luis");
System.out.println(s);
}
persons.addAll(students);
System.out.println("******* HashSet pessoas = professores + alunos");
System.out.println(s);
}
}
28
Unicidade dos Elementos
▸ Num conjunto para se garantir que os elementos são únicos e não existem duplicados tem
de se redefinir os métodos equals e hashCode
▹ Redefinir apenas um deles não é suficiente
▹ O método boolean equals(Object obj) definido na classe Object devolve um
valor lógico que indica se um objeto é igual a outro passado como argumento.
▹ O método int hashCode() é definido na classe Object e tenta devolver, para
todos os objetos, um valor que o identifique univocamente.
29
Redefinir o método equals
@Override
public boolean equals(Object obj) {
Garante que os objetos são
if (obj == null) { da mesma classe
return false;
}
if (getClass() != obj.getClass()) {
Cast para a classe onde se
return false; está a colocar o método
} (neste caso Person)
final Person other = (Person) obj;
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
Verificação da igualdade dos
} dois objetos
30
Redefinir o método equals – versão 2
Auto verificação
@Override
public boolean equals(Object obj) {
if (this == obj) Verificação da validade
return true;
if (obj == null)
Verificação do tipo e cast
return false;
if (getClass() != obj.getClass())
Cast para a classe onde se
return false;
está a colocar o método
Person other = (Person) obj; (neste caso Person)
return Objects.equals(this.name, other.name));
}
Verificação da igualdade dos
dois objetos
31
Redefinir o método equals
▸ Resumo
▹ Os conceitos de identidade e igualdade são diferentes:
▹ Identidade: pode-se verificar se é a mesma referência com ==
▹ Igualdade: podem ser referências diferentes para "o mesmo valor"; verificado com equals
▹ Certificar-se de substituir equals (Object) para que o método redefinido seja sempre chamado.
▹ Incluir uma auto verificação e uma verificação nula para um retorno antecipado em casos extremos
simples.
▹ Usar getClass para permitir que os subtipos tenham a sua própria implementação (mas sem
comparação entre os subtipos) ou usar instanceof e definir equals como final (e os subtipos podem
ser iguais).
▹ Comparar os atributos desejados usando Objects.equals.
32
O “contrato” do método hashCode
▸ Sempre que é chamado no mesmo objeto mais de uma vez durante a execução de uma aplicação
Java, o método hashCode deve retornar consistentemente o mesmo inteiro, desde que nenhuma
informação usada em comparações de igual no objeto seja modificada. Este inteiro não precisa de
permanecer consistente de uma execução da aplicação para outra execução da mesma aplicação.
▸ Se dois objetos são iguais de acordo com o método equals (Object), chamar o método
hashCode em cada um dos dois objetos deve produzir o mesmo resultado inteiro.
▸ Se dois objetos forem diferentes de acordo com o método equals (Object), não é necessário
que a chamada ao método hashCode em cada um dos dois objetos produze resultados inteiros
distintos. No entanto, o programador deve estar ciente de que a produção de resultados inteiros
distintos para objetos desiguais pode melhorar o desempenho das tabelas hash.
33
Redefinir o método hashCode
@Override
return name.hashCode();
34
Redefinir o método hashCode
▸ Resumo
▹ gerar códigos hash é equivalente a “compactar” a igualdade num valor inteiro: objetos iguais devem ter
o mesmo código hash e, por motivos de desempenho, é melhor se o menor número possível de objetos
não iguais partilham o mesmo código hash.
▹ Isso significa que o método hashCode deve sempre ser redefinido se equals é redefinido.
▹ Ao implementar hashCode:
▹ Use os mesmos campos que são usados em equals (ou um subconjunto deles).
▹ É melhor não incluir campos mutáveis.
▹ Considere não chamar hashCode em coleções.
▹ Use um algoritmo comum, a menos que os padrões dos dados os neutralizem.
35
Mapas
▸ Coleções
36
Coleções - Interface Map<K,V>
37
Coleções – Classes que implementam Map<K,V>
▸ HashMap<K,V> - armazena pares de elementos associados
▹ HashMap<Integer, Person> persons = new HashMap<>();
▹ Cria um objeto HashMap chamado persons em que as chaves são do tipo inteiro e os
valores são objetos da classe Person.
▹ O seu comportamento e desempenho são semelhantes ao conjunto análogo HashSet:
também não temos garantia quanto à ordem de iteração e usa uma hash table na sua
implementação (recorrendo aos métodos equals e hashCode para determinar a unicidade).
▸ Outras implementações de mapas (que mantêm a ordem de iteração):
▹ TreeMap<K,V>
▹ LinkedHashMap<K,V>
38
Utilização de Maps
▸ A interface Map, tal como a interface Set, não associa a cada elemento uma posição dentro da coleção, como
acontece na interface List.
▸ Assim a melhor forma para percorrer os elementos de um mapa é através do ciclo for aprimorado ou de um
iterator.
▸ No entanto como no mapa temos uma associação chave/valor podemos percorrer os seus elementos de várias
formas distintas:
▹ Através do acesso às diversas chaves
▹ Através do acesso exclusivo aos valores
▹ Através do acesso aos pares chave/valor
▸ Devemos manter a estratégia de declararmos as variáveis utilizando a interface Map e definir os seus valores
através de uma implementação concreta (ex.: HashMap)
39
Aceder aos elementos de um Mapa
▸ Supondo que se cria um mapa que associa números (Integer) a nomes de pessoas (String):
▹ Integer – porque as classes genéricas não podem trabalhar com tipos primitivos – int. É
preciso utilizar as classes equivalentes)
41
Aceder aos elementos através dos valores
▸ A interface Map tem o método values() que devolve uma Collection<V> com
todos os valores (sem as chaves). Assim, recorrendo ao for-each ou a um iterator
podemos aceder a todos os elementos:
42
Aceder aos elementos através dos pares chave/valor
43
Exemplo Escola,
Algoritmos
▸ Coleções
44
Exemplo Escola
▸ Criar um sistema para registar as notas de alunos.
▸ Serão necessárias as seguintes classes:
▹ Student – informação de um aluno (número e nome)
▹ O número é único, identifica o aluno e deve ser gerado
automaticamente
▹ SchoolClass - informação da turma
▹ Grade - onde se associam os alunos às notas
45
Exemplo Escola
▸ Classe Student public class Student {
46
Exemplo Escola
public int getNumber() {
▸ Classe Student – métodos seletores return number;
}
e modificadores
public String getName() {
return name;
}
@Override
public String toString() {
return number + " - " + name;
}
47
Exemplo Escola
@Override
public int hashCode() {
Integer number = new Integer(this.number);
▸ Classe Student – return number.hashCode();
}
métodos equals e hashCode
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
Usa o HashCode da classe Integer }
if (getClass() != obj.getClass()) {
return false;
}
O número é usado
para distinguir dois return this.number == ((Student) obj).number;
alunos }
48
Exemplo Escola
▸ Classe SchoolClass
49
Exemplo Escola
public String getName() {
▸ Classe SchoolClass – return name;
Métodos (1/2) }
50
Exemplo Escola
public Student remove(int number) {
return students.remove(number);
▸ Classe SchoolClass – }
@Override
public String toString() {
String list = name + ":";
for (Student student : students.values()) {
list += "\n" + student;
}
return list;
}
51
Exemplo Escola
▸ Classe Grade
@Override
public String toString() {
Neste caso consideramos
String grades = "Notas:"; a avaliação como uma
for (Student student : keySet ()) { associação entre aluno e
grades += "\n" + student + ": " + get(student); nota
}
return grades;
}
}
Cuidado!!!
Devemos ter em atenção se não
será necessário redefinir algum dos
métodos herdados.
52
▸ Programa Principal
53
Coleções e a Java Collections Framework
▸ Java Collections Framework (JCF):
▹ É uma arquitetura unificada que inclui interfaces, classes (abstratas e concretas) e algoritmos
(implementados por métodos).
v Como foi dito anteriormente a JCF contém as interfaces que especificam as coleções e classes
(concretas) que implementam essas coleções.
v Além disso ainda tem classes abstratas que implementam parcialmente coleções e algoritmos.
v Os algoritmos permitem várias operações sobre as coleções como por exemplo: a ordenação, a inversão
da ordem dos elementos, a mistura aleatória dos elementos, etc.
54
Java Collections Framework – Algoritmos
▸ Os algoritmos da JCF são fornecidos como métodos estáticos da classe Collections e a maioria aplica-se especificamente a listas,
alguns deles são:
▹sort – ordena uma lista por um critério
▹shuffle – baralha os elementos da lista aleatoriamente
▹reverse – reverte a ordem dos elementos na lista
▹rotate – roda todos os elementos da lista numa distância especificada
▹swap – troca os elementos em posições especificadas de uma lista
▹replaceAll – troca todas as ocorrências de um valor por um outro valor especificado
▹fill – atribui a todos os elementos da lista um valor especificado
▹copy – copia uma lista para outra
▹binarySearch – procura um elemento numa lista com o algoritmo de procura binária
▸ Exemplo de evocação de um algoritmo:
▹ Collections.rotate(names, 4);
▹ Passa os 4 últimos elementos de names para o princípio da lista names pela mesma ordem em que estavam no final da lista.
55
Exemplo Escola - Ordenação dos elementos
de uma coleção
▸ Poderia ser interessante apresentar as notas dos alunos ordenando-os alfabeticamente pelo seu nome
▸ Como foi referido, existem diversos métodos, de classe, que permitem a manipulação dos elementos de
uma coleção. Para ordenar será necessário utilizar o método Collections.sort
▹ A ordenação é feita comparando os elementos da coleção: dados dois elementos é preciso saber se um é "menor",
"igual" ou "maior" que o outro
▹ Existem então três valores possíveis nessa comparação.
▹ A forma mais simples de a fazer é recorrer a um método que devolva um valor negativo em caso de "menor", um
valor positivo em caso de "maior" e zero em caso de igualdade.
56
Interface Comparable<T>
▸ A necessidade de comparar elementos é tão importante e comum que o Java disponibiliza a interface:
▸ A interface Comparable apenas obriga à implementação do método compareTo que recebe um elemento do
mesmo tipo e devolve um valor inteiro positivo, negativo ou zero, consoante o elemento a comparar seja maior, menor
ou igual ao elemento fornecido.
▸ Todas as classes que pretendem ordenar os seus objetos devem implementar esta interface, indicando no método
compareTo o algoritmo de comparação.
57
Exemplo Escola - Ordenação pelo nome dos
Alunos
▸ Para os alunos poderem ser ordenados por nome é preciso que a classe Student implemente a interface
Comparable< Student >:
public class Student implements Comparable<Student> {
...
}
59
Exemplo Escola - Pauta Ordenada
E se
quiséssemos
ordenar agora os
alunos pelo
número ou por
outro valor?
60
Interface Comparator<T>
▸ A solução que utiliza a interface Comparable leva a que a ordenação dos objetos duma classe seja feita
apenas da forma que é definida através do método compareTo
▸ Outra solução é utilizar a interface Comparator:
public interface Comparator<T> {
int compare(T o1, T o2);
}
▸ O método compare funciona da mesma forma que o método compareTo com a diferença que recebe como
argumento dois objetos da mesma classe
▹ Neste caso pode-se criar uma classe separada para cada tipo de comparação que se quer fazer e depois será possível
usá-la no algoritmo de ordenação da classe Collections.
61
Exemplo Escola - Ordenação pelo número dos Alunos
▸ Para os alunos poderem ser ordenados pelo número é preciso criar uma classe que implementa a interface
Comparator<Student> fornecendo o método de comparação compare que compara dois alunos pelos seus
números.
@Override
public int compare(Student student1, Student student2) {
return student1.getNumber() - student2.getNumber();
}
}
62
Exemplo Escola - Ordenação na apresentação das notas
▸ Para produzir uma pauta ordenada pelo número de alunos modificando o toString de Grade é preciso depois de
recolher os alunos numa lista e usar a ordenação com a classe StudentNumberComparator criada:
@Override
public String toString() {
List<Student> students = new ArrayList<>(keySet());
Collections.sort(students, new StudentNumberComparator());
64
Resumindo
▸ Coleção – agregado de elementos de um mesmo tipo
▸ Listas
▹ Classe ArrayList<E> e LinkedList<E>
66
Resumindo
▸ A interface Comparable<T>, através do seu método compareTo, permite a comparação
de objetos (devolvendo < 0, > 0 ou = 0, consoante os valores sejam menores, maiores ou iguais)
▸ A interface Comparator<T>, através do seu método compare, pode ser utilizada por uma
classe onde se define a comparação de dois objetos por uma determinada forma.
▸ Algoritmos
67
Programação Orientada por Objetos
Genéricos
▸ Exemplo de Listas
▸ Exemplo com Listas de Objetos
2
Exemplo de listas
▸ Genéricos
3
Exemplo – Listas
▸ Requisitos :
▹ Pretende-se criar um programa que irá guardar
informação de nomes, de pessoas e de outro tipo de
listas.
▹ Deverá ser possível como é habitual em listas
adicionar, alterar, remover e listar os elementos
das listas.
▹ Como restrição não será possível utilizar as
classes de coleção do Java.
4
Exemplo – Listas
▸ Classe ListOfNames
Tamanho do array
public class ListOfNames {
// continua…
Vamos guardar os
nomes num array.
5
Exemplo – Listas
▸ Classe ListOfNames – métodos add e remove
O array cresce
public void add(String element) { automaticamente quando
if (totalValues == values.length) { atinge o limite
String[] newValues = new String[values.length * 2];
for (int i = 0; i < values.length; i++) {
newValues[i] = values[i];
}
values = newValues;
}
values[totalValues++] = element;
}
@Override
public String toString() {
String result = "[";
boolean first = true;
for (int i = 0; i < totalValues; i++) {
if (first) {
first = false; Listar os nomes
} else { do array.
result += ", ";
}
result += values[i];
}
Escreve os nomes separados
result += "]";
return result; por vírgulas
}
8
Exemplo – Listas
▸ Classe ListOfNames – utilização
public static void testListOfNames() {
ListOfNames names = new ListOfNames();
System.out.println("No início: capacity=" + names.capacity());
names.add("Bruno");
names.add("Fausto");
names.add("José");
names.add("Rui");
names.add("Patricia");
names.add("Joaquim");
System.out.println("Depois de inseridos os elementos: capacity=" + names.capacity());
System.out.println("names=" + names);
System.out.println("size=" + names.size());
System.out.println("names[4]=" + names.get(4));
System.out.println("names[10]=" + names.get(10));
names.remove(4);
System.out.println("Depois de remove(4): names=" + names);
System.out.println("size=" + names.size());
names.set(4, "Silva");
System.out.println("Depois de set(4): names=" + names);
}
9
Exemplo – Listas
NOMES:
No início: capacity=5
Depois de inseridos os elementos: capacity=10
nomes=[Bruno, Fausto, José, Rui, Patricia, Joaquim]
size=6
nomes[4]=Patricia
10
public class Person {
@Override
public String toString() {
return name + " (" + age + " anos)";
}
}
11
Exemplo – Listas
▸ Classe ListOfPerson
Tamanho do array
public class ListOfPerson {
// continua…
Vamos guardar as
pessoas num array
como foi feito com os
nomes
12
Exemplo – Listas
▸ Classe ListOfPerson – métodos add e remove
public void add(Person element) {
if (totalValues == values.length) {
Person[] newValues = new Person[values.length * 2];
for (int i = 0; i < values.length; i++) {
newValues[i] = values[i];
}
values = newValues;
}
values[totalValues++] = element;
}
13
Exemplo – Listas
▸ Classe ListOfPerson – métodos get, set e size
public Person get(int position) {
if ((position >= 0) && (position < totalValues)) {
return values[position];
} else {
return null;
}
}
@Override
public String toString() {
String result = "[";
boolean first = true;
for (int i = 0; i < totalValues; i++) {
if (first) {
first = false;
} else {
result += ", ";
}
result += values[i]; Listar as pessoas
} do array.
result += "]";
return result;
}
15
Exemplo – Listas
▸ Classe ListOfPerson – utilização
public static void testListOfPerson() {
ListOfPerson persons = new ListOfPerson();
System.out.println("No início: capacity=" + persons.capacity());
persons.add(new Person("Maria", 28));
persons.add(new Person("Manuel", 34));
persons.add(new Person("Marta", 45));
persons.add(new Person("Mauro", 53));
persons.add(new Person("Miguel", 19));
persons.add(new Person("Margarida", 26));
System.out.println("Depois de inseridos os elementos: capacity=" + persons.capacity());
System.out.println("persons=" + persons);
System.out.println("size=" + persons.size());
System.out.println("persons[4]=" + persons.get(4));
System.out.println("persons[10]=" + persons.get(10));
persons.remove(4);
System.out.println("Depois de remove(4): persons=" + persons);
System.out.println("size=" + persons.size());
persons.set(4, new Person("Matos", 47));
System.out.println("Depois de set(4): persons=" + persons);
}
16
PESSOAS:
No início: capacity=5
Depois de inseridos os elementos: capacity=10
Exemplo – Listas
pessoas=[Maria (28 anos), Manuel (34 anos), Marta (45 anos), Mauro (53 anos),
Miguel (19 anos), Margarida (26 anos)]
size=6
pessoas[4]=Miguel (19 anos)
pessoas[10]=null
▸ Classe ListOfPerson – utilização Depois de remove(4): pessoas=[Maria (28 anos), Manuel (34 anos), Marta (45
anos), Mauro (53 anos), Margarida (26 anos)]
size=5
Depois de set(4): pessoas=[Maria (28 anos), Manuel (34 anos), Marta (45 anos),
Mauro (53 anos), Matos (47 anos)]
public static void testListOfPerson() {
ListOfPerson persons = new ListOfPerson();
System.out.println("No início: capacity=" + persons.capacity());
persons.add(new Person("Maria", 28));
persons.add(new Person("Manuel", 34));
persons.add(new Person("Marta", 45));
persons.add(new Person("Mauro", 53));
persons.add(new Person("Miguel", 19));
persons.add(new Person("Margarida", 26));
System.out.println("Depois de inseridos os elementos: capacity=" + persons.capacity());
System.out.println("persons=" + persons);
System.out.println("size=" + persons.size());
System.out.println("persons[4]=" + persons.get(4));
System.out.println("persons[10]=" + persons.get(10));
persons.remove(4);
System.out.println("Depois de remove(4): persons=" + persons);
System.out.println("size=" + persons.size());
persons.set(4, new Person("Matos", 47));
System.out.println("Depois de set(4): persons=" + persons);
}
17
Exemplo Listas
▸ Análise das soluções
▹ Quando se consegue saber à priori o número de elementos que se
pretende guardar, a utilização de um array é uma solução eficiente
▹ Quando não se sabe o número de elementos é preferível utilizar uma das
classes de coleção do Java.
▹ Mas as duas soluções são muito parecidas…
▹ Temos muita duplicação de código!
▹ Uma solução para o problema da duplicação de código pode ser criar
uma única lista de Object
18
Exemplo com
listas de Objetos
▸ Genéricos
19
Exemplo – Listas
▸ Requisitos :
▹ Pretende-se criar um programa que irá guardar informação
de nomes, de pessoas e de outro tipo de listas.
▹ Deverá ser possível como é habitual em listas
adicionar, alterar, remover e listar os elementos das
listas.
▹ Como restrição não será possível utilizar as classes de
coleção do Java.
20
Exemplo – Listas
▸ Classe ListOfObject
public ListOfObject() {
values = new Object[DEFAULT_SIZE];
totalValues = 0;
}
// continua…
Vamos guardar os
objetos num array
21
Exemplo – Listas
▸ Classe ListOfObject – métodos add e remove
public void add(Object element) {
if (totalValues == values.length) {
Object[] newValues = new Object[values.length * 2];
for (int i = 0; i < values.length; i++) {
newValues[i] = values[i];
}
values = newValues;
}
values[totalValues++] = element;
}
@Override
public String toString() {
String result = "[";
boolean first = true;
for (int i = 0; i < totalValues; i++) {
if (first) {
first = false;
} else {
result += ", ";
}
result += values[i];
}
result += "]";
return result;
}
24
Exemplo – Listas
▸ Classe ListOfObject – utilização com uma lista de Pessoas
public static void testListOfObject() {
ListOfObject objects = new ListOfObject();
System.out.println("No início: capacity=" + objects.capacity());
objects.add("Bruno");
objects.add("Fausto");
objects.add("José");
objects.add(new Person("Mauro", 53));
objects.add(new Person("Miguel", 19));
objects.add(new Person("Margarida", 26));
System.out.println("Depois de inseridos os elementos: capacity=" + objects.capacity());
System.out.println("objects=" + objects);
System.out.println("size=" + objects.size());
System.out.println("objects[4]=" + objects.get(4));
O código neste caso
System.out.println("objects[10]=" + objects.get(10));
objects.remove(4);
é semelhante ao
System.out.println("Depois de remove(4): objects=" + objects); anterior para a lista
System.out.println("size=" + objects.size()); de pessoas. Mas…
objects.set(4, new Person("Matos", 47));
System.out.println("Depois de set(4): objects=" + objects);
}
25
Exemplo Listas
▸ Análise da solução ListOfObject
▹ Embora a solução com a classe ListOfObject seja semelhante existem alguns problemas.
▹ A colocação de elementos na lista faz-se como anteriormente tirando partido do principio da substituição
▹ objets.add(new Person("Margarida", 26));
▹ O método recebe Object como argumento e estamos a passar um objeto da classe Person
▹ Quando se obtêm elementos da lista a situação é diferente
▹ Person person = (Person)objets.get(4);
▹ É necessário fazer um cast porque o método retorna Object
▹ Outro problema é que o tipo de elementos guardado na lista não é verificado e podemos misturar objetos
de diferentes classes
▹ objets.add("Margarida");
▹ Neste caso adicionámos uma String
26
Exemplo Listas
com Genéricos
▸ Genéricos
27
Exemplo – Listas
▸ Requisitos :
▹ Pretende-se criar um programa que irá guardar informação de
nomes, de pessoas e de outro tipo de listas.
▹ Deverá ser possível como é habitual em listas adicionar,
alterar, remover e listar os elementos das listas.
▹ Como restrição não será possível utilizar as classes de
coleção do Java.
28
Exemplo – Listas
▸ Classe ListaOfNames versus ListOfPerson
public class ListOfName { public class ListOfPerson {
private static final int DEFAULT_SIZE = 5; private static final int DEFAULT_SIZE = 5;
private String[] values; private Person[] values;
private int totalValues; private int totalValues;
// continua… // continua…
29
▸ Classe ListaOfNames versus ListOfPerson
@Override @Override
public String toString() { public String toString() {
String result = "["; String result = "[";
boolean first = true; boolean first = true;
for (int i = 0; i < totalValues; i++) { for (int i = 0; i < totalValues; i++) {
if (first) { if (first) {
first = false; first = false;
} else {
} else { E se result += ", ";
result += ", ";
}
pudéssemos }
result += values[i]; fornecer o tipo result += values[i];
}
} de dados dentro result += "]";
result += "]";
return result; duma variável? return result;
} }
}
31
Tipos Genéricos
▸ Tipo Genérico (Generic) ou Tipo Parametrizado (type parameters).
▹ Na definição de uma classe, ou de um método, é possível indicar (entre < >) um parâmetro que representa um tipo
de dados.
▹ Este parâmetro será utilizado nos locais onde se colocaria o tipo de dados (indicação do tipo dos atributos,
na lista de parâmetros dos métodos, na declaração de variáveis)
public List() {
values = (E[]) new Object[DEFAULT_SIZE];
totalValues = 0;
} Não é possível fazer
// continua… new E[…] em Java
34
Exemplo – Listas
▸ Classe List Genérica – métodos add e remove
public void add(E element) {
if (totalValues == values.length) {
Object[] newValues = new Object[values.length * 2];
for (int i = 0; i < values.length; i++) {
newValues[i] = values[i];
}
values = (E[]) newValues;
} Adicionar e remover
values[totalValues++] = element; elementos do tipo E do
} array.
@Override
public String toString() {
String result = "[";
boolean first = true;
for (int i = 0; i < totalValues; i++) {
if (first) {
first = false;
} else {
result += ", ";
}
result += values[i];
}
result += "]";
return result;
}
37
Exemplo – Listas
▸ Classe List <E> – utilização
▹ No momento da utilização da classe indica-se o tipo pretendido:
▹ List<String> names = new List<String>();
▹ List<Person> persons = new List<Person>();
▹ A partir da Java SE 7 é possível omitir a indicação do tipo, sempre que o compilador consiga
determiná-lo. Utilizando-se a chamada notação diamante <>:
▹ List<String> names = new List<>();
▹ List<Person> persons = new List<>();
▹ Na utilização dos métodos da classe não é necessário fazer qualquer modificação. Continua-se a
poder utilizar elementos de classes derivadas:
▹ Exemplo com uma classe Worker derivada de Person:
persons.set(4, new Worker("Matos", 47));
38
Métodos genéricos - Utilização
▸ A chamada a um método genérico deve indicar o tipo de dados a utilizar:
public class Generics {
...
public static <T> void information(T t) {
System.out.println("T: " + t.getClass().getName());
}
...
}
40
Múltiplos Tipos Parametrizados
▸ Podem ser indicados mais do que um type parameter:
private V value;
}
41
Limitar o Tipo Parametrizado
▸ É possível restringir o type parameter a um determinado tipo ou seus descendentes (através do uso de extends):
public class Association<K extends Number, V extends Person> {
private K key;
private V value;
...
}
Nota: Number tem como descendentes AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte,
Double, Float, Integer, Long, Short ou outros que sejam definidos
42
Limitar o Tipo Parametrizado
▸ A restrição pode ser feita de forma múltipla:
public class A {
...
}
public interface B {
...
}
public interface C {
...
}
44
Erro comum na perceção da Herança
Person
▸ Worker herda de Person:
Worker
List<Worker>
List<Person> List<Worker>
45
Uso de ? (wild-card )
▸ O problema fica resolvido através da indicação de que o tipo de elementos da lista
pode ser qualquer tipo (indicado através de ?) que herde de Person:
//List<Person> error = workers;
List<? extends Person> noError = workers;
▸ ? extends Person indica qualquer tipo de herde de Person (inclusive). Desta forma
indicamos não um tipo de lista mas sim uma "família de tipos de listas" que estão
relacionados pela relação de herança dos seus elementos.
▸ Também é possível a notação ? super T. Neste caso, seriam aceites elementos que
fossem superclasses do tipo T (inclusive).
46
Limitações ao uso de Tipos Parametrizados
▸ Não é possível fazer cast com um type parameter:
example = (E)any;
▸ Tipos Parametrizados não podem ser criados para fazer throw ou catch.
▸ Não pode ser feito polimorfismo de métodos que diferem apenas em Tipos Parametrizados:
public class Wrong {
public void print(List<String> listString) { }
public void print(List<Integer> listInteger) { }
}
47
Resumindo
▸ O uso de Tipos Parametrizados permite definir classes e/ou métodos genéricos que envolvem tipos que
apenas serão concretizados no momento da utilização
▸ Os Tipos parametrizados são, normalmente, representados por uma letra que indica o que o tipo
representa.
▸ É possível omitir o tipo envolvido na utilização de métodos desde que o compilador o consiga determinar
(poderá ser necessário usar a notação <>)
▸ Podem ser utilizados múltiplos tipos parametrizados e podemos limitar a gama de tipos a utilizar
▸ Pode ser necessário recorrer ao uso de ? para indicar relações entre tipos parametrizáveis.
▸ Existem algumas situações em que não é possível usar tipos parametrizáveis.
48
Programação Orientada por Objetos
As coleções
HashSet,
HashMap
Prof. Cédric Grueau
Prof. José Sena Pereira
Departamento de Sistemas e Informática
Escola Superior de Tecnologia de Setúbal
Instituto Politécnico de Setúbal
2022/2023
Sumário
▸ Introdução às coleções
▹ As coleções HashSet e HashMap.
2
Exemplo – Sistema de Apoio Técnico
▸ Sistema de apoio técnico:
▹ Criado para substituir o apoio técnico dado aos clientes da
empresa DodgySoft.
▹ O antigo sistema permitia através do telefone, o
esclarecimento de dúvidas e a resolução de problemas
relacionados com os produtos da empresa.
▹ Dadas as dificuldades pelas quais passa a empresa foi
decidido acabar com o departamento de apoio técnico e
construir um sistema que imitasse as respostas dos técnicos
funcionando online e dando a sensação que o apoio técnico
continuava a ser prestado.
3
Exemplo – Sistema de Apoio Técnico
▸ Utilização Welcome to the DodgySoft Technical Support System.
4
Exemplo – Sistema de Apoio Técnico
5
Exemplo – Sistema de Apoio Técnico
6
Exemplo – Sistema de Apoio Técnico
public class InputReader {
public InputReader() {
reader = new Scanner(System.in);
}
return inputLine;
}
}
7
Exemplo – Sistema de Apoio Técnico
public class Responder {
public Responder() {
▸ Classe Responder }
8
Exemplo – Sistema de Apoio Técnico
public class SupportSystem {
▸ Classe SupportSystem
private InputReader reader;
private Responder responder;
public SupportSystem() {
reader = new InputReader();
responder = new Responder();
}
9
Exemplo – Sistema de Apoio Técnico
public void start() {
▸ Classe SupportSystem – boolean finished = false;
while(!finished) {
String input = reader.getInput();
if(input.startsWith("bye")) {
finished = true;
}
else {
String response = responder.generateResponse();
System.out.println(response);
}
}
printGoodbye();
}
10
Exemplo – Sistema de Apoio Técnico
▸ Classe SupportSystem – métodos printWelcome e printGoodbye
11
Exemplo – Sistema de Apoio Técnico
▸ Sistema de Apoio Técnico:
▹ Tal como está não faz grande coisa
▹ A entrada de dados é sensível a espaços iniciais e finais e a caracteres
maiúsculos e minúsculos.
▹ A resposta é sempre igual
▹ Melhoramentos iniciais
▹ Ser mais flexível na entrada de dados
▹ Ter mais respostas. Podemos selecionar aleatoriamente uma delas.
12
Exemplo – Sistema de Apoio Técnico (2)
public void start() {
boolean finished = false;
▸ Classe SupportSystem printWelcome();
dados. System.out.println(response);
}
}
printGoodbye();
}
13
Exemplo – Sistema de Apoio Técnico (2)
Para se escolher aleatoriamente
public class Responder { uma resposta
14
Exemplo – Sistema de Apoio Técnico (2)
▸ Classe Responder (2) – método fillResponses
responses.add("That sounds odd. Could you describe that problem in more detail?");
responses.add("No other customer has ever complained about this before. \n" +
"What is your system configuration?");
responses.add("That's a known problem with Vista. Windows 7 is much better.");
responses.add("I need a bit more information on that.");
responses.add("Have you checked that you do not have a dll conflict?");
responses.add("That is explained in the manual. Have you read the manual?");
responses.add("Your description is a bit wishy-washy. Have you got an expert\n" +
"there with you who could describe this more precisely?");
responses.add("That's not a bug, it's a feature!");
responses.add("Could you elaborate on that?");
15
Exemplo – Sistema de Apoio Técnico (2)
public String generateResponse() {
▸ Classe Responder (2) –
int index = randomGenerator.nextInt(responses.size());
método
return responses.get(index);
generateResponse (2) }
16
Exemplo – Sistema de Apoio Técnico (2)
Welcome to the DodgySoft Technical Support System.
17
Exemplo – Sistema de Apoio Técnico (2)
▸ Sistema de Apoio Técnico (versão 2):
▹ Está melhor mas ainda tem alguns problemas:
▹ As respostas não dependem do texto que o utilizador introduziu.
▹ Melhoramentos finais
▹ Ter várias respostas associando cada uma delas a uma palavra que possa existir no
texto que o utilizador introduziu.
▹ Ter uma coleção com as palavras que o utilizador introduziu.
▹ Vamos usar uma nova classe de coleção – HashSet – para guardar as palavras do texto
que o utilizador inseriu.
▹ Vamos usar outra classe de coleção – HashMap – para guardar as ligações entre palavras
e respostas associadas.
18
Classe HashSet
▸ A classe de coleção HashSet:
▹ import java.util.Hashset
▹ A classe de coleção HashSet representa um conjunto (set)
▹ Nos conjuntos os elementos não se encontram ordenados.
▹ Neste caso deixamos de saber a posição dos elementos porque simplesmente não
se aplica (ao contrário das listas).
▹ Nos conjuntos não existem elementos repetidos.
▹ A classe HashSet é uma classe genérica
▹ Tal como na classe ArrayList, recebe o tipo dos elementos como parâmetro:
▹ Exemplo: HashSet<Person> , HashSet<Student>, etc.
19
Classe HashSet
▸ Métodos da classe HashSet:
▹ Muitos dos métodos da classe HashSet são semelhantes aos usados pela classe
ArrayList (e por outras classes de coleção):
▹ size – saber o número de elementos que existem,
▹ isEmpty – determinar se existem elementos,
▹ add – adicionar um elemento,
▹ Neste caso, se já existir, o elemento não é adicionado e retorna false
▹ remove – remover um elemento,
▹ Recebe como parâmetro o elemento a remover
▹ clear – remover todos os elementos,
▹ contains – verifica se um elemento existe na coleção.
20
Classe HashSet
▸ Métodos da classe HashSet:
▹ Possui alguns métodos que permitem fazer as tradicionais operações matemáticas
sobre conjuntos:
▹ contains – operação de pertença Î,
▹ addAll – operação de união È,
▹ retainAll – operação de interseção Ç,
▹ removeAll – operação de diferença –,
▹ containsAll – operação de contenção Ì.
Nota: os métodos acima que terminam em All recebem como parâmetro outra coleção.
21
Classe HashSet
System.out.println("*** HashSet professores");
HashSet<String> professors = new HashSet<>();
▸ Classe HashSet - Exemplo professors.add("Ana");
professors.add("Joao");
for(String s: professors) {
System.out.println(s);
}
22
Classe HashSet
HashSet<String> persons = new HashSet<>(professors);
persons.addAll(students);
▸ Classe HashSet - Exemplo System.out.println("*******
HashSet pessoas = professores + alunos");
for (String s : persons) {
System.out.println(s);
}
23
Classe HashSet
HashSet<String> c1 = new HashSet<>();
c1.add("A");c1.add("B"); // c1 = { A, B }
HashSet<String> c2 = new HashSet<>();
c2.add("A");c2.add("B");c2.add("C"); // c2 = { A, B, C }
System.out.println(c1.contains("A"));
System.out.println(c1.contains("C"));
▸ Classe HashSet – Exemplo 2 HashSet<String> union = new HashSet<>(c1);
union.addAll(c2);
System.out.println(union);
HashSet<String> intersection = new HashSet<>(c1);
intersection.retainAll(c2);
System.out.println(intersection);
true
HashSet<String> diference = new HashSet<>(c2);
false
[A, B, C] diference.removeAll(c1);
[A, B] System.out.println(diference);
[C] System.out.println(c2.containsAll(c1));
true
24
Exemplo – Sistema de Apoio Técnico (3)
▸ Classe InputReader –
public HashSet<String> getInput() { método getInput (3)
System.out.print("> "); // print prompt
String inputLine = reader.nextLine().trim().toLowerCase();
25
Exemplo – Sistema de Apoio Técnico (3)
public void start() {
boolean finished = false;
▸ Classe SupportSystem – printWelcome();
26
Classe HashMap
▸ A classe de coleção HashMap:
▹ import java.util.HashMap
▹ A classe de coleção HashMap representa um mapeamento (map)
▹ Nos mapeamentos ou mapas são guardados pares de elementos.
▹ Um dos elementos do par é a chave o outro é o valor. Dizemos que a cada chave está associado um
valor.
▹ As chaves são únicas, não podendo haver repetições.
▹ Os valores podem ser repetidos desde que estejam associados a chaves diferentes.
▹ A classe HashMap é uma classe genérica
▹ No caso dos HashMap como temos pares de elementos devemos fornecer os tipos de cada um dos
elementos do par como parâmetros:
▹ Exemplo: HashMap<Integer,Person> , HashMap<String,String>, etc.
27
Classe HashMap
▸ A classe de coleção HashMap:
▹ A classe de coleção HashMap é utilizada para a associação entre
dois elementos, por exemplo:
▹ Num dicionário temos palavras (chaves) associadas a definições (valores).
▹ HashMap<String,String>
▹ Numa lista telefónica podemos ter números de telefone associados a pessoas.
▹ HashMap<Integer,Person>
28
Classe HashMap
▸ Métodos da classe HashMap:
▹ Métodos comuns a outras coleções:
▹ size – saber o número de elementos que existem,
▹ isEmpty – determinar se existem elementos,
▹ clear – remover todos os elementos.
▹ Métodos comuns:
▹ put – adicionar um par chave-valor,
▹ Recebe a chave e o valor como parâmetros. Se a chave já existir substitui o valor que estava guardado
pelo novo. Retorna o valor anterior ou null se a chave ainda não existia na coleção.
▹ get – vai buscar um valor associado a uma chave,
▹ Recebe como parâmetro a chave. Retorna o valor para essa chave ou null se a chave não existir.
29
Classe HashMap
▸ Métodos da classe HashMap:
▹ Métodos comuns (continuação):
▹ remove – remove da coleção um par chave-valor,
▹ Recebe como parâmetro a chave. Retorna o valor associado à chave ou null se a chave não existir.
▹ containsKey – verifica se já existe um elemento nas chaves,
▹ containsValue – verifica se já existe um elemento nos valores,
▹ keySet – retorna um conjunto com todas as chaves,
▹ values – retorna uma coleção com todos os valores,
▹ entrySet – retorna um conjunto de objetos Map.Entry<K,V>.
▹ Cada elemento do conjunto retornado tem a chave e o valor e é possível obter esses elementos usando,
respetivamente, os métodos getKey() e getValue()
30
Classe HashMap
31
Classe HashMap
HashMap<Integer, String> mapNames = new HashMap<>();
▸ Classe HashMap – Exemplo 2 mapNames.put(13, "Maria");
mapNames.put(43, "Manuel");
mapNames.put(37, "Marco");
mapNames.put(23, "Maria"); //Valor repetido
Pessoas: mapNames.put(43, "Manuel Matos"); //Chave repetida
Marco
Maria
Manuel Matos System.out.println("Pessoas:");
Maria
for (String name : mapNames.values()) {
System.out.println(name);
}
Estamos a aceder apenas
à coleção dos valores
(nomes)
32
Classe HashMap
▸ Classe HashMap – Exemplo 3
HashMap<Integer, String> mapNames = new HashMap<>();
mapNames.put(13, "Maria");
mapNames.put(43, "Manuel");
mapNames.put(37, "Marco");
Pessoas: mapNames.put(23, "Maria"); //Valor repetido
37 - Marco
23 - Maria mapNames.put(43, "Manuel Matos"); //Chave repetida
43 - Manuel Matos
13 - Maria System.out.println("Pessoas:");
for (Map.Entry pair : mapNames.entrySet()) {
System.out.println(pair.getKey() + " - "
+ pair.getValue());
Estamos a aceder ao
}
conjunto das entradas do
mapa
33
Exemplo – Sistema de Apoio Técnico (3)
public class Responder {
▸ Classe Responder (3) // Usado para associar palavras a respostas.
private HashMap<String, String> responseMap;
// Lista de respostas se não existirem palavras reconhecidas.
private ArrayList<String> defaultResponses;
private Random randomGenerator;
public Responder() {
responseMap = new HashMap<String, String>();
defaultResponses = new ArrayList<String>();
fillResponseMap();
fillDefaultResponses();
randomGenerator = new Random();
}
// restantes métodos
34
Exemplo – Sistema de Apoio Técnico (3)
▸ Classe Responder (3) – métodos fillDefaultResponses e pickDefaultResponse
35
Exemplo – Sistema de Apoio Técnico (3)
▸ Classe Responder (3) – método fillResponsesMap
private void fillResponseMap() {
responseMap.put("crash",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");
responseMap.put("crashes",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");
responseMap.put("slow",
"I think this has to do with your hardware. Upgrading your processor\n“
+ "should solve all performance problems. Have you got a problem with\n“
+ "our software?");
responseMap.put("windows",
"This is a known bug to do with the Windows operating system. Please\n" +
"report it to Microsoft. There is nothing we can do about this.");
responseMap.put("bug",
"Well, you know, all software has some bugs. But our software engineers\n“
+ "are working very hard to fix them. Can you describe the problem a bit\n" +
"further?");
36
Exemplo – Sistema de Apoio Técnico (3)
public String generateResponse(HashSet<String> words) {
▸ Classe Responder (3) – método for (String word : words) {
generateResponse String response = responseMap.get(word);
if(response != null) {
return response;
return pickDefaultResponse();
}
37
Exemplo – Sistema de Apoio Técnico (3)
Welcome to the DodgySoft Technical Support System.
38
Exemplo – Coleção de Cromos
▸ Requisitos da aplicação:
▹ Fazer a gestão de uma coleção de cromos.
▹ Cada cromo é caracterizado pelo seu número e pelo seu estado (bom,
razoável, mau).
▹ Na gestão dos cromos deverá ser definido o nome da coleção e o
número de cromos da coleção completa. Os melhores cromos devem
ser guardados numa coleção sem repetições para irem para a
caderneta. Os repetidos serão guardados separadamente.
▹ Na gestão precisamos saber quantos cromos temos, quantos faltam,
adicionar cromos, lista de repetidos, lista dos que temos (números).
39
Exemplo – Coleção de Cromos
public enum CardState {
▸ Classe TradingCard }
GOOD, REASONABLE, POOR
40
Exemplo – Coleção de Cromos
public class TradingCard {
// restante código omitido
▸ Classe TradingCard public CardState getState() {
return state;
}
41
Exemplo – Coleção de Cromos
public class TradingCardCollection { Lista para os repetidos
this.title = title;
this.largestNumber = largestNumber;
repeated = new ArrayList<>();
cards = new HashSet<>();
▸ Classe
} TradingCardCollection
// restante código omitido
}
42
Exemplo – Coleção de Cromos
▸ Classe private boolean validateTradingCard(TradingCard tradingCard) {
return tradingCard != null &&
TradingCardCollection – tradingCard.getNumber() > 0 &&
tradingCard.getNumber() <= largestNumber ;
validateTradingCard e }
addTradingCard
public void addTradingCard(TradingCard tradingCard) {
if (validateTradingCard(tradingCard)) {
if (!cards.add(tradingCard)) {
Se já existir na repeated.add(tradingCard);
coleção }
}
adicionamos aos }
repetidos
43
Exemplo – Coleção de Cromos
▸ Classe
public String toString() {
44
Exemplo – Coleção de Cromos
public class Program {
System.out.println(cards);
}
}
45
Exemplo – Coleção de Cromos
46
Exemplo – Coleção de Cromos
▸ Teste simples da aplicação
System.out.println(cards);
Coleção Teste
Cromos:
#6 (GOOD) #12 (GOOD) #5 (POOR) #12 (GOOD)
Repetidos:
47
Classe HashSet
▸ A classe HashSet usa um método chamado equals para comparar dois elementos.
▹ O método equals, tal como o método toString existe em todos os objetos e é
usado para comparar dois objetos. Por omissão, compara as referências dos
objetos.
▹ A assinatura deste método é:
public boolean equals(Object obj)
▹ O objeto recebido (tipo Object) pode ser de qualquer classe mas espera-se que
seja da classe do objeto a comparar porque senão não será igual (segundo if
do slide seguinte).
48
Classe HashSet
if (getClass() != obj.getClass()) {
return false;
}
final ClasseDoObjeto other = (ClasseDoObjeto) obj;
O getClass à
semelhança do return //teste da igualdade entre os dois objetos (this e other;
toString, equals e }
hashCode é outro dos
métodos que todas as
classes têm por omissão
49
Classe Cromo
if (getClass() != obj.getClass()) {
deverá ser definido na classe }
return false;
50
Classe HashSet
▸ A classe HashSet usa o método equals para comparar dois elementos mas não é ainda
suficiente para que a comparação é seja feita eficientemente para todos os elementos da
coleção. Para que isso aconteça é necessário fornecer mais um método: o método hashCode
▹ O método hashCode, tal como os métodos toString e equals existe também em todos os
objetos e tem uma implementação por omissão que será necessária alterar na maioria
dos casos.
▹ A assinatura deste método é:
public int hashCode()
▹ O valor inteiro retornado deverá ser diferente sempre que os objetos a comparar
forem diferentes.
51
Classe HashSet – Implementação
através de hash table
▸ Um HashSet é implementado através de uma hash table. Uma hash table pode ser vista como um array onde os
elementos são colocados na posição que se obtém pela chamada ao método hashCode (implementação hipotética
do método que adiciona elementos ao conjunto):
public boolean add (Object object) {
int position = object.hashCode();
if (values[position] == null) { //ainda não foi colocado
values[position] = object;
return true;
}
return false;
}
▸ Com esta abordagem a determinação da existência de um elemento no conjunto é muito rápida: basta executar o
método hashCode, no elemento, e verificar se a posição respetiva está ocupada, sem ser necessário percorrer todo
o conjunto, comparando elemento a elemento.
52
Método hashCode
▸ O método hashCode não garante que é devolvido um valor diferente para cada objeto. Tal seria impossível, pois podem
existir mais objetos que os valores disponíveis na gama dos inteiros e o algoritmo a implementar seria tão complexo que
não seria eficiente.
▸ Assume-se que método hashCode devolve um valor que seja aleatoriamente distribuído, por forma a reduzir a hipótese
de repetição (chamada "colisão"). Havendo a certeza que elas vão acabar por existir.
▸ Assim um HashSet é implementado através de uma hash table onde, em cada posição não será colocado o elemento
mas é colocada uma sequência de elementos (designada por bucket - balde) que contêm o mesmo hashCode. Desta
forma a existência de dois objetos com o mesmo hashCode não implica que um vá substituir o outro: ficam ambos
colocados na mesma sequência.
53
Uso do método hashCode
▸ Ao se introduzir um elemento num HashSet o sistema começa por determinar a posição do elemento na hash table
através da chamada ao método hashCode, percorrendo em seguida a sequência de elementos comparando-os
através do método equals.
▸ Por esta razão os métodos equals e hashCode estão intimamente relacionados, não podendo fazer a redefinição
de um sem redefinir o outro (se apenas redefinirmos o equals o hashCode continua a indicar posições diferentes
na hash table para os objetos, permitindo repetições).
54
Definição do método hashCode
▸ Na definição do método hashCode do Java, dada em
http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html é dito que:
▹ Durante a uma execução de uma aplicação Java, a chamada ao método hashCode, para o mesmo objeto, deve devolver
valores iguais. Tal não é garantido para execuções distintas (é preciso ter especial cuidado se forem armazenados hashCode
em bases de dados e posteriormente obtidos ou se tivermos aplicações distribuídas por diferentes máquinas);
▹ Não é obrigatório que dois objetos que não sejam equals tenham hashCode diferentes. Mas uma boa implementação produz
valores tendencialmente distintos para aumentar a performance nas hash table.
55
Exemplo – Coleção de Cromos
public int hashCode() {
return this.number;
▸ Classe TradingCard – }
public boolean equals(Object obj) {
equals e hashCode if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TradingCard other = (TradingCard) obj;
return this.number == other.number;
}
56
Exemplo – Coleção de Cromos
▸ Teste simples da aplicação TradingCard card1 = new TradingCard(12, CardState.GOOD);
TradingCard card2 = new TradingCard(12, CardState.GOOD);
TradingCard card3 = new TradingCard(5, CardState.POOR);
TradingCard card4 = new TradingCard(6, CardState.GOOD);
TradingCard card5 = new TradingCard(12, CardState.REASONABLE);
57
Exemplo – Coleção de Cromos
return cards.isEmpty();
58
Exemplo – Coleção de Cromos
public void addTradingCards(TradingCard[] cards) {
Classe TradingCardCollection – for (TradingCard card : cards) {
addTradingCard(card);
addTradingCards e missingCards }
}
public HashSet<Integer> missingCards() {
HashSet<Integer> missing = new HashSet<>();
for (int i = 1; i <= largestNumber; i++) {
missing.add(i);
}
for (TradingCard card : cards) {
missing.remove(new Integer(card.getNumber()));
}
return missing;
}
59
Exemplo – Coleção de Cromos
▸ Classe TradingCardCollection –
public ArrayList<TradingCard> repetitionsOfCard(int number) {
ArrayList<TradingCard> repetitions = new ArrayList<>();
repetitionsOfCard for (TradingCard card : repeated) {
if (card.getNumber() == number) {
repetitions.add(card);
}
}
return repetitions;
}
60
Exemplo – Coleção de Cromos
public void optimize() {
HashSet<TradingCard> notGood = new HashSet<>(); ▸ Classe TradingCardCollection –
for (TradingCard card : cards) {
if (card.getState() != CardState.GOOD) { optimize
notGood.add(card);
}
}
for (TradingCard card : notGood) {
for(int i=0; i<repeated.size(); i++){
TradingCard iCard = repeated.get(i);
if (iCard.equals(card) && iCard.isInBetterStateThan(card)) {
cards.remove(card);
cards.add(iCard);
repeated.set(i, card);
break;
}
}
} Novo método:
} isInBetterStateThan
61
Exemplo – Coleção de Cromos
▸ Classe TradingCard –
isInBetterStateThan public boolean isInBetterStateThan(TradingCard card) {
62
Exemplo – Coleção de Cromos
TradingCard[] cards = new TradingCard[10];
cards[0] = new TradingCard(1, CardState.GOOD);
cards[1] = new TradingCard(2, CardState.GOOD);
cards[2] = new TradingCard(2, CardState.REASONABLE);
cars.addTradingCards(cards);
cars.addTradingCard(new TradingCard(3, CardState.REASONABLE));
System.out.println(cars);
System.out.println("Faltam: ");
for(int number : cars.missingCards())
System.out.print(number + ", ");
System.out.println();
63
Exemplo – Coleção de Cromos
cars.optimize();
64
Exemplo – Coleção de Cromos (2)
Lista para os repetidos
public class TradingCardCollection {
65
Exemplo – Coleção de Cromos
private boolean validateTradingCard(TradingCard tradingCard) {
return tradingCard != null &&
▸ Classe TradingCardCollection com tradingCard.getNumber() > 0 &&
HashMap – }
tradingCard.getNumber() <= largestNumber ;
validateTradingCard e
public void addTradingCard(TradingCard tradingCard) {
addTradingCard if (validateTradingCard(tradingCard)) {
if (!cards.containsKey(tradingCard.getNumber())) {
cards.put(tradingCard.getNumber(), tradingCard);
} else {
repeated.add(tradingCard);
}
Se já existir na
}
coleção }
adicionamos aos
repetidos
66
Exemplo – Coleção de Cromos (2)
▸ Classe TradingCardCollection public HashSet<Integer> missingCards() {
HashSet<Integer> missing = new HashSet<>();
com HashMap – missingCards
for (int i = 1; i <= largestNumber; i++) {
missing.add(i);
missing.removeAll(cards.keySet());
return missing;
67
Bibliografia
▸ Objects First with Java (6th Edition), David Barnes & Michael
68
Programação Orientada por Objetos
Exceções
▸ Mecanismo de Exceções
▸ Definição de Exceções
2
Agenda de
Endereços
▸ Exceções
Exemplo – Address Book
4
Exemplo – AddressBook
▸ Diagrama de classes da aplicação Address Book:
5
Exemplo – AddressBook
▸ Classes principais da aplicação AddressBook:
▹ ContactDetails – Informação do contacto.
▹ AddressBook – Lista de contactos.
▸ Classes da interface
▹ CommandWords – Define os comandos que podem ser dados
na consola.
▹ Parser – Lê a informação da consola e interpreta-a
retornando-a como um objeto Command.
▹ AddressBookTextInterface – A aplicação em ambiente
de consola.
▹ AddressBookTextDemo – Corre uma demonstração com
alguns contactos já definidos.
6
Exemplo – AddressBook
▸ Classe ContactDetails
public class ContactDetails implements Comparable<ContactDetails> {
private String name;
private String phone;
private String address;
public ContactDetails(String name, String phone, String address) {
if(name == null) {
name = "";
}
if(phone == null) {
phone = "";
}
if(address == null) {
address = ""; }
this.name = name.trim();
this.phone = phone.trim();
this.address = address.trim();
}
// Continua…
7
Exemplo – AddressBook
▸ Classe ContactDetails – métodos seletores e toString
8
Exemplo – AddressBook
▸ Classe ContactDetails – métodos equals e hashCode
public boolean equals(Object other) {
if(other instanceof ContactDetails) {
ContactDetails otherDetails = (ContactDetails) other;
return name.equals(otherDetails.getName()) &&
phone.equals(otherDetails.getPhone()) &&
address.equals(otherDetails.getAddress());
}
else {
return false;
}
}
10
Exemplo – AddressBook
▸ Classe AddressBook e método addDetails
public class AddressBook { Armazena os contactos
numa coleção TreeMap
private TreeMap<String, ContactDetails> book;
private int numberOfEntries;
12
Exemplo – AddressBook
▸ Classe AddressBook – métodos getNumberOfEntries e removeDetails
13
Exemplo – AddressBook
▸ Classe AddressBook – método listDetails
14
Exemplo – AddressBook
▸ Classe AddressBook – método search
public ContactDetails[] search(String keyPrefix) {
List<ContactDetails> matches = new LinkedList<ContactDetails>();
SortedMap<String, ContactDetails> tail = book.tailMap(keyPrefix);
Iterator<String> it = tail.keySet().iterator();
boolean endOfSearch = false;
while(!endOfSearch && it.hasNext()) {
String key = it.next();
if(key.startsWith(keyPrefix)) { Chaves maiores ou
matches.add(book.get(key)); iguais ao prefixo
}
else {
endOfSearch = true;
}
}
ContactDetails[] results = new ContactDetails[matches.size()];
matches.toArray(results);
return results; Devolve um array com
os contactos
}
15
Exemplo – Addressbook
▸ Análise da aplicação AddressBook
▹ A aplicação está funcional mas estamos a assumir que tudo corre bem ou não devemos assumir isso?
▹ Neste caso um objeto AddressBook é um objeto servidor típico.
▹ Não inicia ações, toda a sua atividade é em resposta a pedidos de clientes.
▹ Se pensarmos que o objeto servidor terá clientes que poderão cometer erros inadvertidamente ou mesmo intencionalmente, a
implementação nestes casos terá que ser diferente.
▹ A maior vulnerabilidade num objeto servidor está nos argumentos dos métodos
▹ Os argumentos dos construtores que inicializam o estado do objeto
▹ Os argumentos dos métodos que contribuem para o comportamento do objeto
▹ Devemos colocar as seguintes questões para lidar com as vulnerabilidades:
▹ Que verificações devem ser feitas nos métodos do servidor?
▹ Como reportar os erros aos clientes?
▹ Como devem os clientes antecipar problemas e falhas nos pedidos ao servidor?
▹ Como é que os clientes devem lidar com as falhas nos pedidos ao servidor?
16
Gestão de Erros
▸ Exceções
17
Exemplo – Address Book
▸ Criar uma aplicação para guardar contactos.
▹ Cada contacto regista a informação do nome, telefone e
endereço.
▹ Deve ser possível efetuar as operações habituais de criação,
listagem, alteração e remoção de contactos (operações CRUD).
▹ Deve existir uma forma de procurar contactos pelo nome ou
telefone.
▹ Criar uma interface de consola para a aplicação.
18
Exemplo – Addressbook
▸ Análise da aplicação AddressBook
▹ A aplicação está funcional mas estamos a assumir que tudo corre bem ou não devemos
assumir isso?
▹ A vulnerabilidade nos argumentos dos métodos
▹ Os argumentos dos construtores que inicializam o estado do objeto
▹ Os argumentos dos métodos que contribuem para o comportamento do objeto
▹ Devemos colocar as seguintes questões para lidar com as vulnerabilidades:
▹ Que verificações devem ser feitas nos métodos do servidor?
▹ Como reportar os erros aos clientes?
▹ Como devem os clientes antecipar problemas e falhas nos pedidos ao servidor?
▹ Como é que os clientes devem lidar com as falhas nos pedidos ao servidor?
19
Exemplo – Addressbook
▸ Análise da aplicação AddressBook – método removeDetails
▹ Exemplo de uma vulnerabilidade:
1. Exemplo - chamado com null:
addressBook.removeDetails(null)
public void removeDetails(String key) {
ContactDetails details = book.get(key); 2. book.get(key) retorna null:
details fica com o valor null
book.remove(details.getName());
book.remove(details.getPhone());
numberOfEntries--; } 3. O programa termina com uma exceção na chamada a details.getName():
java.lang.NullPointerException
at java.util.TreeMap.getEntry(TreeMap.java:347)
at java.util.TreeMap.get(TreeMap.java:278)
1. Se a chave não existir book.get(key) retorna null at AddressBook.removeDetails(AddressBook.java:121)
20
Exemplo – Addressbook
▸ Análise da aplicação AddressBook
▹ No exemplo:
▹ Criamos um objeto AddressBook.
▹ Removemos um contacto ( removeDetails )
▹ A aplicação reporta um erro na execução.
▹ De quem é a culpa deste erro?
▹ É preferível anteciparmos esta situação do que passar por este problema.
▹ A maior vulnerabilidade num objeto servidor está nos argumentos dos métodos
▹ Os argumentos dos construtores que inicializam o estado do objeto
▹ Os argumentos dos métodos que contribuem para o comportamento do objeto
▹ A verificação dos argumentos é o que se chama uma medida defensiva
21
Exemplo – Addressbook
▸ Análise da aplicação AddressBook – método removeDetails
▹ Uma solução simples neste caso é fazer a verificação e não agir se a chave a procurar não existir.
22
Exemplo – Addressbook
▸ Análise da aplicação AddressBook – outros métodos
▹ Problemas idênticos existem noutros métodos:
▹ void addDetails(ContactDetails details)
▹ Não verifica se o parâmetro details vem com null
▹ void changeDetails(String oldKey, ContactDetails details)
▹ Oldkey devia existir e details não deveria ter null
▹ ContactDetails[] search(String keyPrefix)
▹ keyPrefix não deve vir a null
▸ Mesmo que se protejam os métodos com verificações o problema não fica totalmente resolvido. É
conveniente em casos destes avisar a aplicação cliente ou mesmo o utilizador. Qual a melhor
maneira de o fazer?
▹ A resposta é: depende! Não existe uma solução única. 23
Reporte de erros
▸ Solução 1: Notificar o utilizador
▹ Através duma mensagem de erro escrita no ecrã ou numa janela de alerta.
▸ Problemas da solução:
▹ Estamos a assumir que existe um utilizador humano com acesso à mensagem.
▹ Nem sempre é verdade. A aplicação do utilizador pode estar a correr num computador
diferente daquele que tem os dados. Pode não existir acesso a um dispositivo de visualização.
▹ Mesmo que o utilizador tenha acesso à informação do erro será que ele pode de alguma forma
corrigi-lo?
▹ A maior parte das vezes o utilizador não tem meios para corrigir o erro.
▹O que pode fazer um utilizador se estiver num terminal de multibanco e receber uma mensagem
NullPointerException ? J
24
Reporte de erros
▸ Solução 2: Notificar a aplicação cliente através de um valor de retorno do método
que está a ser chamado.
▹ No objeto servidor:
26
Reporte de erros
▸ Solução 2: Notificar a aplicação cliente através de um valor de retorno do
método que está a ser chamado.
▸ Problemas da solução:
▹ Por vezes o valor de retorno não permite a utilização dum valor específico para o erro.
▹ Exemplo: um método double getBalance(int accountNumber) que retorna o saldo duma
conta bancária. Como definir um valor de retorno a reportar que o número da conta está errado?
▹ Mesmo que exista o retorno com a informação do erro como se garante que a aplicação cliente vai
verificar e utilizar esse valor de retorno?
▹ A aplicação pode decidir ignorar o valor de retorno do método:
28
Exemplo – Addressbook
▸ Análise da aplicação AddressBook
▹ A aplicação está funcional mas estamos a assumir que tudo corre bem ou não devemos assumir isso?
▹ A vulnerabilidade nos argumentos dos métodos
▹ Os argumentos dos construtores que inicializam o estado do objeto
▹ Os argumentos dos métodos que contribuem para o comportamento do objeto
▹ Devemos colocar as seguintes questões para lidar com as vulnerabilidades:
▹ Que verificações devem ser feitas nos métodos do servidor?
▹ Como reportar os erros aos clientes?
▹ Como devem os clientes antecipar problemas e falhas nos pedidos ao servidor?
▹ Como é que os clientes devem lidar com as falhas nos pedidos ao servidor?
29
Reporte de erros
▸ Solução 1: Notificar o utilizador
▹ Através duma mensagem de erro escrita no ecrã ou numa janela de alerta.
▸ Problemas da solução:
▹ Estamos a assumir que existe um utilizador humano com acesso à mensagem.
▹ Mesmo que o utilizador tenha acesso à informação do erro será que ele pode de alguma forma corrigi-lo?
▸ Solução 2: Notificar a aplicação cliente através de um valor de retorno do método que está a ser chamado.
▸ Problemas da solução:
▹ Por vezes o valor de retorno não permite a utilização dum valor específico para o erro.
▹ Mesmo que exista o retorno com a informação do erro como se garante que a aplicação cliente vai verificar e
utilizar esse valor de retorno?
30
Reporte de erros – Exceções
▸ Solução 3: Notificar a aplicação cliente através da utilização do mecanismo de Exceções.
▹ Em caso de erro é lançada uma exceção a informar do erro e a aplicação cliente é obrigada a tratar esse
erro se não quiser evitar que a aplicação termine abruptamente reportando a informação da exceção.
▸ Uma Exceção é um sinal gerado pela máquina virtual de Java em tempo de execução, que é enviado ao
programa indicando a ocorrência de um erro recuperável.
▸ Funcionamento do mecanismo de exceções:
▹ Quando existe um erro é criado um objeto com a informação do problema.
▹ A aplicação é interrompida e é passado à aplicação o objeto criado com a informação do problema. Diz-
se que foi lançada uma Exceção.
▹ O controlo do programa passa depois para um bloco de tratamento do erro caso este tenha sido criado,
caso contrário a aplicação é interrompida e é reportada a exceção ocorrida.
▹ Depois do erro tratado a execução da aplicação continua normalmente.
31
Reporte de erros
▸ Exemplo do lançamento duma exceção:
33
Classe das exceções
▸ As exceções lançadas são representadas por classes que formam uma hierarquia com
base na classe Exception:
▹ Para cada tipo de exceção existe uma classe própria
▹ Todas as classes de exceção têm por convenção o sufixo Exception
34
Consequências das exceções
▸ Quando uma exceção é lançada o método onde está termina imediatamente.
▹ Não existe valor de retorno
▹ O controlo da aplicação não volta ao ponto onde o método foi chamado
▹ Neste caso a aplicação não pode continuar ignorando o que aconteceu
▹ Mas a aplicação pode capturar a exceção
39
Tratamento de exceções
▸ Podem existir vários blocos catch de tratamento de exceções
▹ Cada bloco processa o tratamento de um tipo de exceção
▹ Apenas um dos blocos é executado quando ocorre uma exceção dentro do bloco try
▹ O primeiro que for do tipo da exceção que foi lançada será o que é executado
▹ Como existe uma hierarquia de exceções, as exceções mais genéricas devem ser as últimas a ser capturadas
try {
...
ref.process();
...
}
catch(EOFException e) {
// código de tratamento da exceção end-of-file
...
}
catch(FileNotFoundException e) {
// código de tratamento da exceção file-not-found
...
}
catch(Exception e) { Exceção mais genérica
// código de tratamento da exceção genérica (Exception)
...
} 40
Tratamento de exceções
▸ Podem existir vários blocos catch de tratamento de exceções
▹ Multi-catch (a partir do Java 7)
▹ Permite usar o mesmo bloco de catch para mais do que um tipo de exceção:
try {
...
ref.process();
...
}
catch(EOFException |FileNotFoundException e){
// código de tratamento para ambos os tipos de exceção
...
}
41
Tratamento de exceções
▸ A clausula finally
▹ A clausula finally é um bloco de código que aparece depois do(s) bloco(s) catch e
que é executado sempre, exista ou não exista exceção
try {
// Instruções com verificação de ocorrência de exceção
}
catch(Exception e){
// Código do tratamento da exceção
}
finally{
// Ações comuns que devem ser executadas haja ou não haja exceção.
}
42
Exceções – Procura Ascendente de um Catch
▸ Quando o método que lança a exceção não tem um catch para a exceção lançada, a procura do bloco catch
adequado propaga-se pelos métodos clientes até se encontrar um catch para essa exceção ou se atingir o método
main e terminar o programa.
metodo3(){
// método onde ocorre ou que lança uma exceção "e"
}
43
Definição de
Exceções
▸ Exceções
44
Categorias de exceções
Object
Classes do Utilizador
▹ Subclasses de RunTimeException
▹ Usadas para falhas que não são previstas
▹ A recuperação é pouco provável
MinhasExceçõesNãoVerificadas
45
Exceções verificadas
▸ As exceções não verificadas podem ou não ser capturadas e tratadas pela aplicação
▹ Se acontecerem e não forem tratadas a aplicação termina
▸ As exceções verificadas são feitas para serem capturadas e tratadas pela aplicação
▹ O compilador assegura que são capturadas dando erro de compilação se isso não acontecer.
▹ Estas exceções se forem convenientemente tratadas as falhas serão recuperáveis
▹ Os métodos que lançarem exceções verificadas devem incluir na assinatura do método a palavra reservada
throws seguida da exceção ou exceções que lançam (separadas por vírgulas)
▹ Exemplo:
// código do método
} IOException:
É uma exceção verificada do Java
que pode ser lançada neste método 46
Exceções – Definição de novas exceções
▸ Para definir novas exceções:
▹ Cria-se uma classe derivada de RuntimeException para criar uma nova exceção não verificada pelo compilador
▹ Cria-se uma classe derivada de Exception para uma exceção verificada pelo compilador.
▸ A definição de novas exceções oferece uma informação mais precisa do problema.
Guarda a
public class NoMatchingDetailsException extends Exception {
informação sobre a
private String key; chave que originou
o erro
public NoMatchingDetailsException(String message, String key){
super(message);
this.key = key;
}
Vai obter-se a
public String getKey(){ key específica
que originou o
return key;
erro
}
public String toString(){
return "No details matching '" + key + "' were found.";
}
} 49
Exceções – Definição de Novas Exceções
▸ Neste exemplo adiciona-se no lançamento da exceção a informação especifica da exceção:
public ContactDetails getDetails(String key) throws NoMatchingDetailsException {
...
throw new NoMatchingDetailsException("Chave com problemas", key);
...
}
▸ No caso da exceção ser gerada, temos acesso, através da variável “e” (declarada como parâmetro do
catch), à chave que originou o erro:
...
try { Acesso à informação
... da key que originou
contact = agenda.getDetails("Maria"); o erro
...
}
catch (NoMatchingDetailsException e) {
System.out.println("A chave " + e.getKey() + " deu problemas");
...
} 50
Exceções – Recuperação de Erros
// Tenta guardar a agenda telefónica
▸ Os clientes devem tratar as boolean success = false;
int attempts = 0;
notificações de erro. do {
▹
try {
Verifique os valores addressbook.saveToFile(fileName);
retornados. success = true;
}
▹ Não ignore as exceções. catch (IOException e) {
▸ Inclua código para tentar
System.out.println("Incapaz de guardar o
ficheiro " + nomeFicheiro );
recuperar do erro. attempts++;
if (attempts < MAX_TENTATIVAS) {
▹ Frequentemente isso implica fileName = alternativeName;
um ciclo. }
}
} while (!success && attempts < MAX_ATTEMPTS);
if (!success) {
//Relate o problema e desista;
}
51
Exceções – Mais Comuns
▸ ArithmeticException ▸ StringIndexOutOfBoundsException
Indica falhas no processamento aritmético, tal como uma Indica a tentativa de usar um índice numa string fora
divisão inteira por 0. dos seus limites
▸ ArrayIndexOutOfBoundsException ▸ NumberFormatException
Indica a tentativa de conversão de uma string para um
Indica a tentativa de acesso a um elemento de um array fora
formato numérico, mas que o seu conteúdo não
dos seus limites: ou o índice é negativo ou maior ou igual ao representava um número para aquele formato.
tamanho do array.
▸ NullPointerException
▸ IndexOutOfBoundsException Indica que a instrução tentou usar null onde era
Indica a tentativa de usar um índice fora dos limite de uma necessária uma referência a um objeto
tabela. ▸ IllegalArgumentException
▸ ArrayStoreException Quando o argumento do método tem um valor impossível
Indica a tentativa de armazenamento de um objeto inválido ▸ IOException
numa tabela. Indica a ocorrência de qualquer tipo de falha em
operações de entrada e saída.
▸ NegativeArraySizeException
Indica a tentativa de criar uma tabela com dimensão negativa.
52
Resumindo
▸ A linguagem Java permite o tratamento de situações de exceção de uma forma normalizada através da utilização de 5 palavras
chave correspondentes a cláusulas especiais, a saber:
▹throws public void method() throws ExcecaoVerificadaHerdaDeException {
▹throw
// […] implementação do método
throw new ExcecaoVerificadaHerdaDeException(...);
▹catch
}
// Na chamada do método:
▹finally try{
// […] instruções com chamada ao metodo()
}
catch (ExcecaoVerificadaHerdaDeException e) {
// Tratamento da exceção "e" do tipo
// ExcecaoVerificadaHerdaDeException
}
catch (RuntimeException e) {
// Tratamento da exceção "e" do tipo RuntimeException
}
finally{
// Bloco opcional se existir é sempre executado
} 54
Bibliografia
▸ Objects First with Java (6th
Edition), David Barnes & Michael
Kölling, Pearson Education
Limited, 2016
▹ Capítulo 14 (14.1 a 14.6)
55
Programação Orientada por Objetos
Entradas e
saídas
▸ Serialização
2
Entrada e Saída
de Dados
▸ Entradas e Saídas
Exemplo – Address Book
▸ Criar uma aplicação para guardar contactos.
▹ Cada contacto regista a informação do nome, telefone e endereço.
▹ Deve ser possível efetuar as operações habituais de criação, listagem,
alteração e remoção de contactos (operações CRUD).
▹ Deve existir uma forma de procurar contactos pelo nome ou telefone.
▹ Criar uma interface de consola para a aplicação.
▹ Guardar os contactos e o resultado das procuras em ficheiro
4
Exemplo – AddressBook
▸ Diagrama de classes da aplicação Address Book:
5
Exemplo – AddressBook
▸ Classes da aplicação
AddressBook:
▹ ContactDetails – Informação
do contacto.
▹ AddressBook – Lista de
contactos.
▹ AddressBookDemo – Cria um
livro de contactos com alguns dados
para testes.
▹ AddressBookFileHandler –
é responsável pela leitura e escrita
em ficheiro da lista de contactos e
dos resultados de procura dos
contactos.
6
Exemplo – AddressBook
▸ Classe AddressBookDemo
public class AddressBookDemo {
private AddressBook book;
public AddressBookDemo() {
ContactDetails[] sampleDetails = {
new ContactDetails("david", "08459 100000", "address 1"),
new ContactDetails("michael", "08459 200000", "address 2"),
new ContactDetails("john", "08459 300000", "address 3"),
new ContactDetails("helen", "08459 400000", "address 4"),
new ContactDetails("emma", "08459 500000", "address 5"),
new ContactDetails("kate", "08459 600000", "address 6"),
new ContactDetails("chris", "08459 700000", "address 7"),
new ContactDetails("ruth", "08459 800000", "address 8"),
};
book = new AddressBook();
for(ContactDetails details : sampleDetails) {
book.addDetails(details);
}
}
public AddressBook getBook() { Cria um AddressBook
return book; com uma lista inicial de
} contactos
} 7
Exemplo – AddressBook
▸ Classe AddressBookFileHandler
Guarda a referência do
livro de contactos que irá
public class AddressBookFileHandler {
ser utilizado na escrita e
private AddressBook book; na leitura para ficheiro
private static final String RESULTS_FILE = "results.txt";
Nome do ficheiro
public AddressBookFileHandler(AddressBook book) { que irá guardar o
resultado da última
this.book = book;
procura
}
Recebe o livro de
// Continua… contactos no
construtor
Ø Antes de vermos a implementação será necessário perceber como funciona a escrita e leitura de ficheiros …
8
Entradas e saídas
Ø Em Java os ficheiros e as pastas (ou diretórios) são representados pela classe File
Ø Importa-se como java.io.File
Ø Em java 7 foram acrescentadas a interface Path e as classes Files e Paths importadas de
java.nio.file dedicadas igualmente à manipulação de ficheiros.
▹ CONSTRUTORES
Classe File:
File(String caminho) construtor de directórios/ficheiros
File(String caminho&filename) construtor com caminho e nome do ficheiro
▹ MÉTODOS
boolean canRead() ficheiro/directório pode ser lido
boolean canWrite() pode-se gravar no ficheiro/directório
boolean delete() apaga ficheiro/directório
boolean exists() verifica se ficheiro/directório existem
boolean isAbsolute() verifica se caminho é absoluto
boolean isDirectory() verifica se objecto é directório
boolean isFile() verifica se objecto é ficheiro
boolean mkdir() cria directório do objecto
boolean mkdirs() cria directórios do caminho
boolean renameTo(String novo) muda nome do ficheiro/directório para novo
9
Entradas e saídas
▸ Exemplo de utilização da classe File
10
Entradas e saídas
▸ Para além da representação dos ficheiros o Java inclui classes dedicadas à escrita e à leitura
dos ficheiros em disco.
▹ Existem classes independentes para a escrita e para a leitura de ficheiros.
▸ De acordo com o tipo de informação que é armazenada, os ficheiros podem ser classificados
como ficheiros de texto ou ficheiros binários
▹ Os ficheiros de texto guardam caracteres e podem ser lidos e editados por qualquer aplicação de edição de texto
(notepad, word, etc.)
▹ Na realidade a informação é guardada em bytes que representam caracteres de acordo com um determinado standard
(ASCII, Unicode, etc.)
▹ Neste caso existe alguma interpretação tanto na leitura como na escrita destes ficheiros de texto
▹ Os ficheiros binários guardam a informação em bytes que não é possível interpretar sem a ferramenta
adequada. Por exemplo imagens, música, vídeo, etc.
▹ Neste caso não existe qualquer interpretação dos bytes escritos ou lidos.
11
Entradas e saídas
▸ Para a leitura e escrita de ficheiros de texto existem várias classes que formam uma hierarquia e
que derivam respetivamente das classes abstratas Reader e Writer.
12
Entradas e saídas
▸ Para a leitura e escrita de ficheiros binários existem várias classes que formam uma hierarquia e que
derivam respetivamente das classes abstratas InputStream e OutputStream.
13
Entradas e saídas
▸ A leitura e escrita de ficheiros independentemente de serem de texto ou binários é
feita sequencialmente.
▸ Os processos de escrita ou de leitura de ficheiros são sempre feitos em
3 etapas:
1. Abrir o ficheiro
2. Operação de escrita ou de leitura
3. Fechar o ficheiro.
▸ As operações com ficheiros estão também sujeitas a muitos tipos de falhas, por isso a
maior parte delas pode levantar exceções, que são sempre verificadas (obrigam à
utilização de blocos try-catch)
14
Entradas e saídas
▸ Hierarquia de exceções de io (input/output = entrada/saída) do Java
15
Ficheiros de texto
▸ Exemplo da escrita de um ficheiro de Texto usando a classe FileWriter.
19
Exemplo – Address Book
▸ Criar uma aplicação para guardar contactos.
▹ Cada contacto regista a informação do nome, telefone e endereço.
▹ Deve ser possível efetuar as operações habituais de criação, listagem,
alteração e remoção de contactos (operações CRUD).
▹ Deve existir uma forma de procurar contactos pelo nome ou telefone.
20
Exemplo – AddressBook
▸ Classes da aplicação AddressBook:
▹ ContactDetails – Informação do contacto.
▹ AddressBook – Lista de contactos.
▹ AddressBookDemo – Cria um livro de contactos
com alguns dados para testes.
▹ AddressBookFileHandler – é responsável pela
leitura e escrita em ficheiro da lista de contactos
e dos resultados de procura dos contactos.
21
Exemplo – AddressBook
▸ Classe AddressBookFileHandler
Guarda a referência do livro
de contactos que irá ser
public class AddressBookFileHandler { utilizado na escrita e na
leitura para ficheiro
private AddressBook book;
private static final String RESULTS_FILE = "results.txt";
22
Exemplo – AddressBook
▸ Classe AddressBookFileHandler – métodos makeAbsoluteFilename e getProjectFolder
writer.write(details.toString());
Escreve para disco
writer.write(‘\n’);
os vários contactos
writer.write(‘\n’); do array results
}
writer.close();
Este método terá de ser
} chamado dentro de um
bloco try-catch
24
public void showSearchResults() {
BufferedReader reader = null;
Exemplo –
try {
File resultsFile = makeAbsoluteFilename(RESULTS_FILE);
reader = new BufferedReader(new FileReader(resultsFile));
AddressBook
System.out.println("Results ...");
String line; line = reader.readLine();
while(line != null) {
▸
System.out.println(line);
Classe line = reader.readLine();
AddressBookFileHandler }
System.out.println();
– método }
showSearchResults catch(FileNotFoundException e) {
System.out.println("Unable to find the file: " + RESULTS_FILE);
}
catch(IOException e) {
System.out.println("Error encountered reading the file: " +
RESULTS_FILE);
}
finally {
Lê do ficheiro os if(reader != null) {
resultados da busca try { reader.close();
e mostra-os no ecrã }
catch(IOException e) {
System.out.println("Error on closing: " + RESULTS_FILE);
}
}
}
}
25
Exemplo – AddressBook
▸ Classe AddressBookFileHandler – método addEntriesFromFile
▸ Neste caso a escrita para ficheiro no modo binário é feita utilizando a classe ObjectOutputStream
▹ O procedimento é semelhante à escrita em modo de texto mas as classes envolvidas são
diferentes e também estamos a escrever um objeto completo para o disco.
▹ É necessário igualmente usar este método dentro de um bloco try-catch
27
Exemplo – AddressBook
▸ Classe AddressBookFileHandler – método readFromFile
29
Serialização
▸ Além das formas tradicionais de escrita e leitura para ficheiro existe ainda uma outra forma
chamada serialização de objetos
▹ Neste caso é escrito em modo binário para o ficheiro um objeto de uma determinada classe incluindo os
objetos que são referenciados nos seus atributos
▸ O processo de leitura é chamado desserialização de objetos
▹ Agora são restaurados a partir do ficheiro os objetos que anteriormente foram serializados pela mesma
ordem em que foram guardados
30
Serialização
▸ A serialização é aplicável apenas a instâncias de classes que implementem a interface
Serializable
31
Serialização
▸ Ao declarar que uma classe implementa a interface Serializable, o compilador gera dois métodos privados para essa
classe:
▹ void writeObject ( ObjectOutputStream out ) throws IOException
▹ Object readObject ( ObjectInputStream in ) throws IOException, ClassNotFoundException
n Um objeto “ObjectOutputStream” representa um canal binário que trabalha diretamente sobre um ficheiro e
que armazena objetos e valores simples, usando o método writeObject() o qual implementa um algoritmo
de serialização (serialize).
n Um objeto “ObjectInputStream” representa um canal especial que trabalha diretamente sobre um
ficheiro e lê objetos e valores simples, usando o método readObject() o qual implementa um algoritmo
de desserialização (deserialize).
32
Serialização – Gravação em Ficheiro
▸ Considerando que
▹ A classe Persons inclui um array de objetos da classe Person
▹ E que a classe Person possui um atributo yearOfBirth da classe Date
▹ O método abaixo vai gravar num ficheiro binário
▹ um objeto da classe Persons,
▹ com todos os elementos do array de objetos (com todos os objetos da classe Person)
▹ e para cada objeto da classe Person, o nome e a respectiva data de nascimento
▹ Num ficheiro binário serializado a partir do qual será possível reconstituir completamente o objeto
da classe Persons
public static void saveFile(Persons listOfPersons, String filename) {
try {
ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(filename));
oos.writeObject(listOfPersons);
oos.flush(); oos.close();
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
33
Serialização – Leitura de Ficheiro
▸ Considerando que
▹ Foi gravado através de uma ObjectOutputStream num qualquer ficheiro binário, um objeto da classe
Persons
▹ É possível lê-lo do ficheiro reconstituindo completamente o seu estado no momento da gravação através do
método abaixo:
public static Persons readSerializedFile(String filename) {
Persons listOfPersons;
try {
ObjectInputStream ois = new ObjectInputStream( new FileInputStream(filename));
listOfPersons = (Persons) ois.readObject();
ois.close();
}
catch (IOException e) {
System.out.println(e.getMessage());
listOfPersons = new Persons(10);
}
catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
listOfPersons = new Persons(10);
}
return listOfPersons;
}
34
Serialização – modificador transient
▸ Na serialização o Java escreve no ficheiro todos os atributos, não static, da classe que implementa a interface
java.io.Serializable.
▸ Podemos indicar que não pretendemos que um atributo seja escrito (eventualmente porque o seu tipo é de uma
classe que não implementa a interface Serializable) desde que utilizemos o modificador transient:
▹ private transient Color cor; //Color não é Serializable
▸ Se for importante a informação do atributo teremos que implementar as nossas versões dos métodos que fazem a
escrita e leitura da informação:
▹ private void writeObject(java.io.ObjectOutputStream oos) throws IOException
▹ private void readObject(ObjectInputStream ois) throws ClassNotFoundException,
IOException
▹ Estes métodos devem chamar, normalmente no seu início, o comportamento por omissão:
▹ oos.defaultWriteObject();
▹ ois.defaultReadObject();
35
Bibliografia
36
Programação Orientada por Objetos
JavaFX – Eventos
e Painéis
2
Programação por
Eventos
▸ Eventos e Paineis
3
JavaFX - Eventos
1. Ação: quando o
▸
Na programação baseada em eventos o utilizador prime o
código é executado quando ocorre o botão …
acontecimento (evento) 2. Evento: é gerado um
▹Por exemplo, podemos querer que o evento …
programa execute uma operação em 3. Executa Código: se o
resposta a ações do utilizador tais como: programador
▹Premir um botão do rato associou código ao
▹Deslocar o rato evento gerado esse
código é executado.
▹Premir um botão
▹Premir uma tecla
4
JavaFX – Eventos
▸ A classe Event public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
javafx.event.Event;
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>(){
▸Podemos olhar para um evento (acontecimento) como @Override
sendo um sinal, representado por um objeto, enviado public void handle(ActionEvent event) {
ao programa, assinalando a ocorrência de uma ação. System.out.println("Hello World!");
▹Geralmente os eventos ocorrem na sequência de }
});
ações do utilizador (mas nem sempre)
▹O programa pode reagir ao evento ou ignorá-lo.
StackPane root = new StackPane();
root.getChildren().add(btn);
▹Um evento é originado por um objeto fonte, que primaryStage.setScene(new Scene(root, 300, 250));
pode ser conhecido através do método: primaryStage.show(); }
Object getSource()
Dentro do método handle seria possível aceder ao botão, que gerou o evento, através de:
▸ O método handle recebe como argumento um objeto da classe Event, ou respetivas subclasses, que
contém informação sobre o evento (ex. getSource() devolve o objeto onde foi gerado o evento)
▸ Na abordagem tradicional teríamos que criar uma classe que implementasse a interface
EventHandler<ActionEvent> (fazendo o override do método handle) e passar um objeto dessa
classe como argumento para o setOnAction.
6
JavaFX - Eventos
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
//...
btn.setOnAction(new ButtonAction("Hello World!"));
//...
7
JavaFX – Eventos (classe anónima)
▸ Para não se criar uma classe específica para cada ação associada a cada evento, é possível
recorrer à criação de classes anónimas (estender uma classe já existente ou implementar uma
interface) :
▹ http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
▸ Com a utilização de uma classe anónima é possível declarar e instanciar uma classe num único
passo.
▸ Na definição de uma classe anónima utiliza-se o operador new, seguido do nome da interface
(ou da classe que se pretenda estender), seguido de eventuais argumentos do construtor
(apenas () quando se trata de uma implementação de interface), seguido do corpo da classe:
new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
} 8
JavaFX - Eventos
▸ Como associar ações do utilizador a nós do grafo de cena?
1. Definir o evento a capturar na respetiva propriedade do nó em causa. public void start(Stage primaryStage) {
Exemplo para o nó btn: primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setOnAction(eventHandler) btn.setText("Say 'Hello World'");
btn.setOnAction( new EventHandler<ActionEvent>() {
2. Associar a essa propriedade o (novo) tratador de eventos (definido em @Override
função do tipo de evento que pretendemos capturar): public void handle(ActionEvent event) {
System.out.println("Hello World!");
EventHandler<EventoACapturar>()
}
3. Redefinir o método handle do tratador de eventos passado, colocando
});
StackPane root = new StackPane();
nesse método o código a ser executado root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
public void handle (EventoACapturar event) primaryStage.show();
}
9
JavaFX – Eventos (expressões lambda)
▸ O uso de classes anónimas veio simplificar bastante a indicação do código a executar (método
handle) quando o evento é gerado.
▸ No Java 8 é possível simplificar a utilização de implementações de interfaces anónimas que
apenas possuem um método (as chamadas interfaces funcionais), através da utilização do
conceito de expressão lambda: http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
▸ Uma expressão lambda (o seu nome advém do estudo “λ-calculus” realizado pelo matemático
Alonzo Church na década de 1930) permite representar um método indicando apenas o(s) seu(s)
parâmetro(s) e o seu corpo (omitindo o seu nome).
▸ Assim, o anterior método handle poderia ser representado por:
return a + b;
} poderia ser representado por (a, b) -> a + b
11
JavaFX – Eventos
▸ Em resumo, em Java 8, a associação do método do evento pode ser feita:
▹ Através da criação de uma classe específica que implementa a interface do evento:
public class ActionButton implements EventHandler<ActionEvent> {
private String message;
public ActionButton(String message) { this.message = message; }
public String getMessage() {return message; }
public void setMessage(String message) {this.message = message;}
@Override
public void handle(ActionEvent event) { System.out.println(message); }
}
btn.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event){
System.out.println("Hello World!"); } });
13
Paineis
▸ Eventos e Paineis
14
JavaFX – Gestores de Painéis
▸ Até ao momento, temos inserido os nós folha diretamente nas janelas ou no painel StackPane, sem
nos preocuparmos em definir as suas posições (absolutas ou relativas).
▸ Em aplicações reais isso não é aceitável e temos de especificar as posições dos componentes por
forma a produzir uma interface gráfica do utilizador (GUI) facilmente compreensível.
▸ Duas abordagens para inserir componentes gráficos:
▹ Rígida: especificar onde os componentes deverão ser colocados, através de coordenadas
absolutas
▹ Usada apenas na prototipagem rápida de aplicações
▹ A apresentação final fica dependente da plataforma
▹ Não suporta adequadamente o redimensionamento
do container (janela ou painel)
▹ Flexível: utilização de painéis
▹ Adapta a posição dos componentes gráficos
a possíveis redimensionamentos da janela
▹ Apresentação final adapta-se à plataforma utilizada
15
JavaFX – Gestores de Painéis
▸ O package layout - javafx.scene.layout.*;
▹ O JavaFX disponibiliza no package layout vários modelos pré-definidos para disposição de componentes.
▹ Os componentes que estabelecem e gerem os diferentes modelos de disposição de elementos são denominados
painéis (Pane).
▹ Os elementos gráficos são adicionados a esses painéis e são dispostos de acordo com o modelo definido por
esse painel.
▹ Vamos ver apenas quatro dos mais comuns.
16
JavaFX – Gestores de Painéis
▸ BorderPane
javafx.scene.layout.BorderPane;
17
import javafx.scene.layout.BorderPane;
JavaFX – Gestores de Painéis
public class BorderPaneExample extends Application {
@Override
public void start(Stage primaryStage) {
19
JavaFX – Gestores de Painéis Um painel VBox
distribui os
componentes na
▸ HBox e VBox vertical
javafx.scene.layout.HBox;
javafx.scene.layout.VBox; public void start(Stage primaryStage) {
primaryStage.setTitle("BOXs Layout");
Button btn1 = new Button("Botao 1");
20
JavaFX – Gestores de Painéis
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
HBox hbox = addBotoes();
root.setTop(hbox);
VBox vbox = addTextos();
▸ Painéis Compostos root.setCenter(vbox);
Scene scene = new Scene(root, 700, 500);
▹ Objetivo: criar um BorderPane primaryStage.setScene(scene);
primaryStage.show();
21
JavaFX – Gestores de Painéis
▸ Painéis Compostos
▹ Objetivo: criar um BorderPane com um
HBox no topo e um VBox no centro.
▹ Estrutura de nós do grafo de cena:
1. Root (BorderPane)
1.1 Top – HBox – (área de botões)
1. Botão Vermelho
2. Botão Azul
1.2 Center - VBox – (área do texto)
1. Text ("Font Serif")
2. Text ("Font SanSerif")
3. Text ("Font Monospaced")
22
Exemplo de
Eventos e Paineis
▸ Eventos e Paineis
23
JavaFX- Eventos : Exemplo
▸ Objetivo: Construir uma aplicação com a interface gráfica onde os textos mudam
de vermelho para azul e vice-versa em função do botão acionado.
24
JavaFX- Eventos : Exemplo
Objetivo
Criar a estrutura principal da aplicação.
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
1. Criar um BorderPane
HBox hbox = addButtons();
2. Adicionar os Botões root.setTop(hbox);
3. Adicionar os Textos VBox vbox = addTexts();
root.setCenter(vbox);
4. Criar a Cena Scene scene = new Scene(root, 700, 500);
5. Associar a Cena ao Stage primaryStage.setScene(scene);
primaryStage.show();
6. Mostrar }
25
JavaFX- Eventos : Exemplo
26
JavaFX- Eventos : Exemplo private VBox addTexts() {
VBox vbox = new VBox();
vbox.setPadding(new Insets(10));
Objetivo vbox.setSpacing(10);
addTexts(vbox);
return vbox;
Criar o painel com os textos (será colocado no }
centro).
private void addTexts(VBox vbox) {
1. Criar um painel VBox, definindo as suas vbox.getChildren().addAll(
características createText("Font Serif","Serif",30),
createText("Font SanSerif","SanSerif",50),
2. Adicionar os Textos como filhos do painel
);
createText("Font Monospaced","Monospaced",70)
27
JavaFX- Eventos : Exemplo
Objetivo: Ação a executar pelos botões.
1. Obter o botão que gerou o evento (getSource())
2. Seguir a hierarquia para obter o painel principal
3. Obter o painel (VBox) que tem os textos
4. Percorrer todos os nós do painel e, caso sejam textos, modificar a sua cor
28
JavaFX- Eventos : Exemplo
29
Resumindo
▸ Eventos
▹ A Programação baseada em eventos permite interagir com uma interface gráfica
▹ A Classe Event
▹ Uma ação do utilizador sobre um componente do GUI
▹ Faz com que esse objeto gere um evento
▹ Evento esse que, ao ser apanhado pelo “handler” apropriado, despoleta a execução do código
desse “handler”
▹ Para que um qualquer componente do GUI (nó) reaja a diferentes ações do utilizador basta
criar um “handler” para cada uma dessas ações no respetivo componente.
▸ Painéis (Pane)
▹ BorderPane (cinco zonas: top, bottom, left, right, center)
▹ GridPane (uma grelha)
▹ HBox e VBox (dispõem os componentes horizontal e verticalmente)
▹ Painéis compostos por painéis (podemos sempre inserir painéis em painéis)
30
Leitura Complementar
▸ Chapter 3 – Lambdas and Properties Pgs 61 a 73
▸ Chapter 4 – Layouts and UI Controls Pgs 91 a 101
▸ Documentação:
▹ http://docs.oracle.com/javase/8/javafx/api/toc.htm
▸ Eventos:
▹ http://docs.oracle.com/javase/8/javafx/api/javafx/event/package-summary.html
▹ http://docs.oracle.com/javase/8/javafx/events-tutorial/events.htm
▸ Painéis
▹ http://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/package-
frame.html
▹ http://docs.oracle.com/javase/8/javafx/layout-tutorial/index.html
31
Programação Orientada por Objetos
JavaFX – Controlos
2
CoNtrolos do JavaFX
▸ JavaFX – Controlos
JavaFX – Controlos
▸ As classes para criar controlos de interface
com o utilizador encontram-se no pacote
javafx.scene.control
▸ Exemplos:
▹ Button
▹ TextField
▹ Label
▹ ListView
4
JavaFX – Controlos
public void start(Stage primaryStage) {
▹ No exemplo inicial: primaryStage.setTitle("Hello World!");
Button btn = new Button();
▹ Definiu-se um botão! btn.setText("Say 'Hello World'");
btn.setOnAction(
new EventHandler<ActionEvent>(){
@Override
Button btn = new Button(); public void handle(ActionEvent event) {
btn.setText("Say 'Hello World'"); System.out.println("Hello World!");
}
});
▹
StackPane root = new StackPane();
Associou-se ao botão um handler para o root.getChildren().add(btn);
evento Action primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
btn.setOnAction( //[…] );
5
JavaFX – Controlos
public void start(Stage primaryStage) {
primaryStage.setTitle("Botão Imagem");
▸ Colocar uma imagem num botão Image imageOk = new Image(getClass().getResourceAsStream(
"icons/ok.png"), 40, 40, false, false);
Button btn = new Button("OK", new ImageView(imageOk));
primaryStage.setScene(scene);
primaryStage.show();
}
6
JavaFX – Controlos
TextField textFieldName = new TextField();
▸ TextField – Criação e Utilização textFieldName.setMinSize(12, 10);
TextField
7
JavaFX – Controlos
▸ Label – Criação e Utilização Label nameLabel = new Label("Nome");
Label listLabel = new Label("ListaPessoas");
Label
8
JavaFX – Controlos
ListView
▸ ListView – Criação e Utilização
9
JavaFX – Classe FXCollections
▸ A classe FXCollections disponibiliza um conjunto de métodos de classe (static) que
permitem obter e manipular "coleções sincronizáveis":
▹ observableArrayList()
▹ observableSet()
▹ observableHashMap()
▹ replaceAll
▹ reverse
▹ rotate
▹ sort
▹ etc.
▸ As "coleções sincronizáveis" ao serem modificadas (adicionar ou remover elementos) tentam
atualizar os objetos com que estão sincronizadas (normalmente elementos gráficos). Na
próxima aula será explicado este mecanismo de sincronização.
10
Exemplo
Controlos simples
▸ JavaFX – Controlos
11
mplo Completo (ListView, TextField)
PanelTexto
O nome introduzido é transferido
para a lista após validado pelo
utilizador através do botão OK! PanelList
12
JavaFX – Exemplo: adicionarPanelTexto
private TextField textFieldName; Atributo na Classe
public void addTextPanel (Pane root) {
textPanel.getChildren().addAll(nameLabel,this.textFieldName,okButton);
root.getChildren().add(textPanel);
}
13
JavaFX – Exemplo: adicionarPanelList
this.items= FXCollections.observableArrayList();
this.listOfNames = new ListView<>();
ListView
this.listOfNames.setPrefSize(100,120);
this.listIfNames.setItems(this.items);
listPanel.getChildren().addAll(namesLabel,this.listOfNames);
root.getChildren().add(listPanel);
}
14
JavaFX – Exemplo: adicionarNomeLista
15
JavaFX – Exemplo: Apagar elementos da lista
Objetivo:
Selecionar um nome da lista e apagá-lo.
16
JavaFX – Exemplo: Apagar elementos da lista
public void addListPanel(Pane painel) {
...
17
JavaFX – Exemplo: Aceder aos elementos selecionados
Singular
Numa Lista podemos ter: o String item =
1. Selecção Singular list.getSelectionModel().getSelectedItem();
2. Selecção Múltipla
Múltipla
podemos aceder aos: o ObservableList<String> items=
1. Itens selecionados list.getSelectionModel().getSelectedItems();
2. Índices dos itens selecionados
o ObservableList<Integer> indexes =
list.getSelectionModel().getSelectedIndices();
18
JavaFX – Exemplo Controlos Simples
19
Desenhador de
Formas
▸ JavaFX – Controlos
20
JavaFX Exemplo – Desenhador de formas
21
JavaFX Exemplo – Desenhador de formas
▸ Serão apresentadas duas ListView que permitem indicar a forma e a cor pretendidas. Estas
serão colocadas num painel VBox;
▸ Através do uso do rato indica-se (carregando) o ponto inicial e (levantando) o ponto final;
▸ Em oposição à criação de objetos das subclasses de Shape, apresentados na aula de
introdução, será criada uma zona de desenho (Canvas), e utilizam-se os métodos de desenho
de GraphicsContext para criar todas as formas;
▸ GraphicsContext (http://docs.oracle.com/javase/8/javafx/api/javafx/scene/canvas/GraphicsContext.html) é uma classe que contém toda
a informação necessária ao desenho (cores, espessuras, etc.) e os métodos necessários:
setFill, getFill, setStroke, getStroke, fillArc, strokeArc,
beginPath, closePath, moveTo, lineTo, fill, stroke, fillOval,
strokeOval, fillRect, strokeRect, fillRoundRect, strokeRoundRect,
strokeLine, fillText, strokeText, etc.
22
JavaFX Exemplo – Alternativas de formas
public enum Shape {
Oval, Retangulo, RetArredondado;
//Foi quebrada a norma de escrita em MAIÚSCULAS para não
//rescrever o toString para ficar "bonitinho"
Retângulos e Retângulos
switch (this) {
case Oval:
Arredondados graphicsContext.fillOval(x, y, width, height);
break;
case Retangulo:
graphicsContext.fillRect(x, y, width, height);
break;
▸É criado o método que desenha a case RetArredondado:
graphicsContext.fillRoundRect(x,y, width, height,
forma, em função do valor atual width /Shape. ROUNDING,altura/ Shape. ROUNDING);
break;
}
}
}
23
JavaFX Exemplo – Seletor de Cores e Formas
public class ShapeColorSelector extends VBox {
25
JavaFX Exemplo – Área de desenho
public class DrawingArea extends Canvas {
27
JavaFX Exemplo – Área de desenho
▸ O método associado ao setOnMouseReleased é responsável por armazenar as
coordenadas do ponto onde termina a forma a desenhar-se, por calcular os limites da forma,
por preparar o ambiente de desenho e, finalmente, por mandar desenhar a forma:
private void drawShape(MouseEvent event) {
double xFinal = event.getX();
double yFinal = event.getY();
29
JavaFX Exemplo – método start
30
Resumindo
▸ Controlos
▹ Button – inserir imagem num botão
1. Criar uma imagem associada a um ficheiro (Image).
2. Associar a imagem ao botão (ImageView).
33
Programação Orientada por Objetos
JavaFX –
Propriedades
▸ Visualizador de Pessoas
▹ Criação de uma interface gráfica
▹ Especializar (herança) objetos gráficos para
representar a nossa informação
▸ Propriedades e Binding
2
EXEMPLO VISUALIZADOR
PESSOAS
▸ JavaFX – Propriedades
Exemplo – Visualizador de Pessoas
▸ Requisitos da aplicação:
▹ Criar uma aplicação que permita gerir a informação de
um grupo de pessoas.
▹ A informação a guardar para cada pessoa é apenas o
nome e a idade.
▹ Deve ser possível adicionar, alterar, visualizar e apagar
uma pessoa.
▹ A visualização deve ser feita em JavaFX em duas cenas
diferentes, uma que mostra as pessoas e outra que
visualiza apenas uma pessoa.
4
Criação de uma interface gráfica
public class Person {
▸ Supor que temos uma classe Person, que private static final int MINIMUM_AGE = 0;
representa a informação associada a uma private static final int MAXIMUM_AGE = 120;
private String name; private int age;
pessoa:
▹ Nome protected static boolean isNameValid(String name) {
return (name != null && !name.isEmpty());
▹ Idade }
protected static boolean isAgeValid(int age) {
▸ Definir a classe com a garantia de não haver return ((age >= MINIMUM_AGE) && (age <= MAXIMUM_AGE)); }
public Person(String name, int age) {
informação inconsistente: if (!isNameValid(name)) {
throw new IllegalArgumentException("O nome da pessoa não
▹ Existe o nome é válido!");
}
▹ A idade é [0,120] if (!isAgeValid(age)) {
▸
throw new IllegalArgumentException("A idade da pessoa
Em caso de valores impossíveis o construtor não é válida!");
lança exceções }
this.name = name;
this.age = age;
}
5
public String getName() {
Classe Person (cont.) }
return name;
▸
public Roster() {
Optar por um conjunto pois não devem existir persons = new HashSet<>();
}
pessoas repetidas
public void addPerson(Person person) {
▸ Implementar os modificadores (adicionar e }
persons.add(person);
▸ É possível definir a classe Roster como uma @Override public boolean remove(Object person)
{
extensão de HashSet<Person>. System.out.println("Removi: " + person);
return super.remove(person);
▸ Os métodos addPerson, removePerson e }
}
containPerson, passam a ser os add, remove
//Criar a lista
final ObservableList<Person> personsList = FXCollections.observableArrayList(persons);
final ListView<Person> list = new ListView<>(personsList);
10
Visualizador da coleção Roster (cont.)
//Criar o painel dos botões
HBox buttonsPanel = new HBox(10);
//Botão criar
Button createButton = new Button("Criar...");
createButton.setOnAction(e -> list.getScene().setRoot(new PersonViewer(persons, null)));
//Botão editar
Button editButton = new Button("Editar...");
editButton.setOnAction(e -> {
Person person = list.getSelectionModel().getSelectedItem();
if (person != null) {
list.getScene().setRoot(new PersonViewer(persons, person)); } });
//Botão apagar
Button removeButton = new Button("Apagar");
removeButton.setOnAction(e -> {
Person person = list.getSelectionModel().getSelectedItem();
if (person != null) {
personsList.remove(person);
persons.remove(person);
}
});
setPadding(new Insets(10));
setSpacing(10);
getChildren().setAll(listLabel, list, buttonsPanel);
}
}
▸ Nesta classe só se definiu:
▹ O construtor para inserir os elementos gráficos necessários
▹ Os EventHandler dos botões que manipulam a coleção (argumento do construtor – final)
Todas as restantes funcionalidades são herdadas do painel VBox
▸ A alternância entre ecrãs é feita através de xxx.getScene().setRoot(), onde xxx representa um
elemento gráfico colocado no painel. Assim ter-se-á acesso à scene onde o painel está a ser apresentado.
12
Visualizador de Pessoa
▸ É criada uma subclasse de GridPane para apresentar uma Person.
O painel apresentará:
▹ Os rótulos
▹ A caixa de texto para o nome
▹ O slider para a idade
▹ Os botões
public class PersonViewer extends GridPane {
13
Visualizador de Pessoa – criação do Slider
▸ A criação do Slider deve utilizar os limites da idade definidos na classe Pessoa,
acrescentamos, à classe atual (PersonViewer), um método que cria e devolve um
Slider, adaptado à informação das idades das pessoas:
public class PersonViewer extends GridPane {
public AgeSlider() {
setMin(Person.getMinimumAge());
setMax(Person.getMaximumAge());
setShowTickLabels(true);
setShowTickMarks(true);
setMajorTickUnit(10);
}
}
15
Criação do Slider - nova classe (cont.)
▸ Neste segundo caso, será necessário substituir a criação do Slider pela criação de um objeto da
nova classe (AgeSlider) na classe PersonViewer,
public class PersonViewer extends GridPane {
16
Visualizador de Pessoa (cont.)
▸ Depois de criados os elementos para apresentar a informação da pessoa convém acrescentar à janela
PersonViewer os botões aceitar e cancelar:
//Botão aceitar
Button acceptButton = new Button("Aceitar");
acceptButton.setOnAction(e -> {
if (person == null) { //Criar
try {
persons.addPerson(new Person(nameField.getText(), (int) ageSlider.getValue()));
} catch (Exception ex) {
}
} else { //Atualizar
person.setName(nameField.getText());
person.setAge((int) ageSlider.getValue());
}
nameField.getScene().setRoot(new RosterViewer(persons));
});
//Posicionar os nós
setPadding(new Insets(10));
setVgap(10);
setHgap(10);
add(nameLabel, 0, 0);
add(nameField, 1, 0);
add(ageLabel, 0, 1);
add(ageSlider, 1, 1);
add(acceptButton, 0, 2);
add(cancelButton, 1, 2);
}
}
18
Gravar a informação
▸ Com esta interface é possível ir acrescentando, modificando e apagando a informação associada às pessoas.
▸ A manutenção da informação entre execuções do programa passa por gravar, num ficheiro, toda a informação
▸ É preciso tornar Serializable as classes (Roster e Person) e definir métodos, ReadRoster() e writeRoster(), para ler (no início
do programa) e escrever (associado ao botão fechar ) a informação de/para o ficheiro:
@Override
public void start(Stage primaryStage) {
final Roster persons = Roster.readRoster();
Scene scene = new Scene(new RosterViewer(persons), 400, 300);
primaryStage.setTitle("Gestão de Pessoas");
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(e -> persons.writeRoster());
primaryStage.show();
}
19
Gravar a informação
public class Roster extends HashSet<Person> implements Serializable {
▸ JavaFX – Propriedades
Exemplo – Visualizador de Pessoas
▸ Requisitos da aplicação:
▹ Criar uma aplicação que permita gerir a informação de
um grupo de pessoas.
▹ A informação a guardar para cada pessoa é apenas o
nome e a idade.
▹ Deve ser possível adicionar, alterar, visualizar e apagar
uma pessoa.
▹ A visualização deve ser feita em JavaFX em duas cenas
diferentes, uma que mostra as pessoas e outra que
visualiza apenas uma pessoa.
22
Exemplo – Visualizador de Pessoas
23
Sincronização da informação
▸ A escolha da introdução da informação relativa à idade através de um Slider é
visualmente apelativa mas não permite a introdução de informação de forma precisa,
▸ O ideal era ter a possibilidade de introdução da informação através do Slider e de uma
Caixa de Texto, de forma sincronizada:
24
Sincronização da informação
▸ O Slider tem o getter e o setter tradicionais: getValue() e setValue(). No entanto o valor é "armazenado" dentro de um
objeto especial que se obtém através de valueProperty() e não num simples double.
▸ Analogamente, a Caixa de Texto tem o getter e o setter tradicionais: getText() e setText(), mas o seu valor é
"armazenado" dentro de um objeto especial que se obtém através de textProperty() e não numa simples String.
▸ Estes objetos especiais, as "propriedades", permitem associações entre eles, por forma a sincronizar a sua
informação. Esta sincronização pode ser bidirecional (a alteração de um implica, automaticamente, a alteração do
outro) ou unidirecional (só a mudança de um é que influência a mudança do outro).
26
Propriedades – Listener
▸ As propriedades permitem, para além da sincronização, associar um Listener, que será
executado sempre que o valor da propriedade é alterado.
▸ Desta forma podemos implementar comportamentos genéricos, que excedem a simples
sincronização do valor. Por exemplo, para uma propriedade DoubleProperty (exemplo com o
Slider da idade):
ageSlider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue,
Number newValue) {
"Código a executar quando a propriedade muda de valor. Temos acesso:
à propriedade (observable),
ao valor original (oldValue)
ao novo valor (newValue)"
}
});
27
Propriedades no JavaFX
▸ As propriedades são um mecanismo fundamental do JavaFX.
▸ Todos os objetos gráficos têm propriedades para os seus diversos valores. O teste
hasProperties() verifica se um Node tem ou não propriedades.
▸ As propriedades são acessíveis através de métodos da forma xxxProperty().
28
Slider e Caixa de Texto
▸ Para resolver o problema de implementar um Slider sincronizado com uma Caixa de Texto, vai ser
necessário criar uma classe que substitua a classe Slider, pelo menos nas suas funcionalidades
básicas utilizadas no presente projeto (aceder através de getValue() e setValue()).
▸ Assim, na classe PersonViewer, substitui-se a criação do AgeSlider pela criação de um objeto da
nova classe (AgeViewer):
29
Classe AgeViewer
public class AgeViewer extends HBox {
▸ A implementação da
classe AgeViewer private final AgeSlider ageSlider;
private final TextField ageField;
apenas necessita dos public AgeViewer() {
atributos para conter os ageSlider = new AgeSlider();
ageField = new TextField();
elementos gráficos, do ageField.setPrefWidth(50);
ageField.textProperty().bindBidirectional(ageSlider.valueProperty(),
construtor e do getter e NumberFormat.getIntegerInstance());
setter: setSpacing(10);
getChildren().addAll(ageSlider, ageField);
}
public double getValue() {
return ageSlider.getValue();
}
public void setValue(double age) {
ageSlider.setValue(age);
}
}
30
Resumindo
▸ Criação de interfaces gráficas através do acrescento de novas classes que permitem a visualização dos
objetos já existentes no domínio do problema.
▸ Para cada classe poderá ser criado um "visualizador” (implementa as operações básicas – CRUD: Create, Read,
Update e Delete).
▸ A criação dos visualizadores é feita por herança de objetos gráficos já existentes. Uma vez que se pretende
apresentar informação dos vários atributos, recorre-se, normalmente, à extensão das classes que permitem
agrupar/apresentar diversos elementos gráficos – os painéis. No respetivo construtor (que recebe o objeto a
apresentar) são criados todos os elementos gráficos necessários.
▸ A funcionalidade fica completa através da criação dos diversos EventHandler e da ligação (binding) entre
as propriedades do objeto e a dos elementos gráficos. Esta ligação pode ser feita de forma bidirecional
(bindBidirectional) ou unidirecional (bind), para sincronizar os valores ou genericamente através da
criação de um Listener.
31
Leitura Complementar
▸ Chapter 3 – Lambdas and Properties Pgs 74 a 89
Chapter 4 – Layouts and UI Controls Pgs 91 a 101 e 108 a 111
▸ Propriedades e binding:
▸ http://docs.oracle.com/javase/8/javafx/properties- binding-
tutorial/binding.htm#sthref8
32
Programação Orientada por Objetos
JavaFX – Controlos II
▸ Menus em JavaFX
2
LISTVIEW E COMBOBOX
▸ JavaFX – Controlos II
JavaFX - Controlos
▸ As classes para criar controlos
encontram-se no pacote
▹ javafx.scene.control
▸ Exemplos anteriores:
▹ Button
▹ TextField
▹ Label
▹ ListView
4
JavaFX – Revendo o exemplo da ListView
o ListView –
Criação e Utilização
ListView
1. Criar um objeto do tipo
ListView.
2. Criar uma
ObservableList de
Strings e associá-la ListView<String> listOfNames = new ListView<>();
à ListView
ObservableList<String> items=FXCollections.observableArrayList();
listOfNames.setItems(items);
2. Criar uma
ObservableList de
Strings e associá-la ComboBox<String> listOfNames= new ComboBox<>();
à ComboBox
ObservableList<String> items=FXCollections.observableArrayList();
listOfNames.setItems(items);
7
Tabs, Accordion
e TitledPane
▸ JavaFX – Controlos II
8
JavaFX – Exemplo: Tab
Uma forma simples de gerir a alternância entre vários painéis é através da utilização de um
TabPane com vários Tab associados.
TabPane
Tab
9
JavaFX – Exemplo: Tab
Objetivo: Ter dois Painéis A e B, e alternar entre um e outro consoante o Tab selecionado.
public PanelWithTabs () {
TabPane tabPane = new TabPane();
Tab tabA= new Tab("Painel A");
Tab tabB= new Tab("Painel B");
tabA.setContent(new PanelA());
tabB.setContent(new PanelB());
tabPane.getTabs().addAll(tabA,tabB);
this.getChildren().add(tabPane);
}
}
public PanelA() {
this.getChildren().add(new Label("Painel A"));
}
}
10
JavaFX – Exemplo: Tab
Objetivo: Ter dois Painéis A e B, e alternar entre um e outro consoante o Tab selecionado.
11
JavaFX – Exemplo: Accordion
Outra forma simples de gerir a alternância entre vários painéis é através da utilização de um Accordion com
vários TitledPane associados.
TitledPane
Accordion
12
JavaFX – Exemplo: Accordion
Objetivo: Ter dois Painéis 1 e 2, e alternar entre um e outro consoante a seleção.
public PanelWithAccordion() {
Accordion accordion = new Accordion();
TitledPane panel1 = new Panel1();
TitledPane panel2 = new Panel2();
accordion.getPanes().add(panel1);
accordion.getPanes().add(panel2);
this.getChildren().add(accordion);
}
}
public Panel1() {
this.setText("Painel 1");
this.setContent(new Label("Painel 1"));
}
}
13
JavaFX – Exemplo: Accordion
15
Menus em
JavaFX
▸ JavaFX – Controlos II
16
JavaFX – Exemplo: Menus
Em JavaFX podem usar-se as seguintes classes para definir menus:
• MenuBar
• Menu
• MenuItem
• CheckMenuItem
• RadioMenuItem
• SeparatorMenuItem
• ContextMenu
MenuItem MenuBar
Menu
SeparatorMenuItem
CheckMenuItem
17
JavaFX – Exemplo: Menus
Preparação do Layout
public class PanelWithMenu extends BorderPane {
public PanelWithMenu() {
MenuBar menuBar = new MenuBar();
Menu setupMenu = new Menu("Configurar");
MenuItem setupMenuA = new MenuItem("Adicionar A");
MenuItem setupMenuB = new MenuItem("Adicionar B");
setupMenu.getItems().addAll(setupMenuA, setupMenuB);
Menu showMenu = new Menu("Visualizar");
MenuItem showMenuA = new MenuItem("ver A");
CheckMenuItem showMenuB = new CheckMenuItem("ver B");
showMenu.getItems().addAll(showMenuA,new SeparatorMenuItem(), showMenuB);
Menu exitMenu = new Menu("Sair");
MenuItem closeMenu = new MenuItem("Fechar");
exitMenu.getItems().add(closeMenu);
menuBar.getMenus().addAll(setuMenu,
showMenu,
exitMenu);
this.setTop(menuBar);
}
}
18
JavaFX – Exemplo: Menus Preparação do funcionamento
Ex: Sair da aplicação através do MenuItem Fechar do Menu Sair
menuBar.getMenus().addAll(setuMenu,
showMenu,
exitMenu);
this.setTop(menuBar);
}
}
19
JavaFX – Exemplo: Menus
Objetivo: Alternar entre painéis, consoante a opção do Menu selecionada.
Solução: Usar o layout BorderPane para a Janela. Definir dois painéis (panelA e panelB), colocar na zona central
o panelA ou o panelB consoante a opção do menu.
22
CheckBox e
RadioButton
▸ JavaFX – Controlos II
23
JavaFX – Exemplo: CheckBox
CheckBox
• Determinado e selecionada.
• Indeterminado
24
JavaFX – Exemplo: CheckBox
Objetivo: Mostrar um botão com um icon sempre que a
CheckBox sassociada está selecionada.
Passo 1
1. Definir os vários arrays
2. Definir as imagens a mostrar
3. Definir as CheckBox
25
JavaFX – Exemplo: CheckBox
Passo 2
Definir a ação a realizar quando se altera a
seleção de uma CheckBox recorrendo à
utilização de “listeners” da propriedade selected
26
JavaFX – Exemplo: Radio Buttons
RadioButton
ToogleGroup
27
JavaFX – Exemplo: Radio Buttons
Objetivo: Ter uma aplicação que em função do
RadioButton selecionado, muda a cor do texto
apresentado.
Passo 1
1. Definir os RadioButton
2. Definir o ToogleGroup
3. Associar os RadioButton ao ToogleGroup
4. Criar o Text
Passo 2
Definir as ações a realizar quando existe um
evento nos botões. Uma ação para cada botão.
29
JavaFX- Eventos : Exemplo
30
Resumindo
▸ ListView e ComboBox
▹ Permitem apresentar e manipular coleções de elementos.
▹ A ListView permite seleção Múltipla ou Simples.
▹ A ComboBox só permite a seleção de um elemento (Simples).
▸ Tab
▹ Através de um controlo TabPane, podemos implementar a alternância entre vários painéis.
▹ Associando um painel a um Tab e por sua vez os vários Tabs a um TabPane.
▸ Accordion
▹ Através de um controlo Accordion, também é possível implementar a alternância entre painéis.
▹ Criando os vários TitledPane e associando-os ao Accordion.
▸ Menu
▹ É possível definir uma hierarquia de menus e submenus, usando as classes MenuBar, Menu, MenuItem,
CheckMenuItem, RadioMenuItem, SeparatorMenuItem.
▸ CheckBox
▹ Através de um controlo CheckBox, podemos implementar a seleção de uma opção.
▸ RadioButton
▹ Para implementar a escolha exclusiva através de RadioButton, temos que definir um ToggleGroup e associar cada
RadioButton ao grupo criado. 31
Leitura Complementar
▸ Chapter 4 – Layouts and UI Controls Pgs 101 a 108
http://docs.oracle.com/javase/8/javafx/user-interface- tutorial/combo-
box.htm#BABJCCIB
http://docs.oracle.com/javase/8/javafx/user-interface-
tutorial/menu_controls.htm#BABGHADI
https://docs.oracle.com/javafx/2/ui_controls/checkbox.htm
http://docs.oracle.com/javase/8/javafx/user-interface- tutorial/radio-
button.htm#BABBJBDA
▸ Controlos UI
https://docs.oracle.com/javafx/2/ui_controls/overview.htm
32
Programação Orientada por Objetos
JavaFX – Janelas
e Formas
▸ JavaFX + CSS
▸ Exemplo
2
JavaFX – definição
de estilo com CSS
Ø JavaFX – utilização de estilo com CSS
Cascadind Style Sheets - CSS
▸ O css por defeito para todas as aplicações JavaFX é escrito num ficheiro
chamado modena.css, que pode ser encontrado no ficheiro jar do JavaFX
runtime, jfxt.jar, localizado na pasta de instalação do Java.
5
Atribuição de estilos aos nós
6
Propriedade de um componente: ID
▸ Assim como numa interface web, as propriedades CSS são Ficheiro .java
aplicadas em seletores que podem ser:
button = new Button("Conta");
▹ o id: dá um nome particular a um nó. button.setId("account");
8
Propriedade de um componente: pseudo classe
▸ uma pseudo classe: é uma indicação que permite especificar quando deve ser aplicado o
estilo (ao passar o rato sobre o botão, ao clicar, ao clicar nele, ...).
▸ Essa indicação pode ser usada em classes e também em identificadores.
▸ Ele é concatenado a uma classe.
▹ Exemplo: .Button:focus, .Button:hover , #valueName:hover.
9
JavaFX + CSS:
Exemplo
Ø JavaFX – utilização de estilo com CSS
Layout da aplicação
▸ Modena.css demo.css
11
Estrutura da aplicação formulário
▸ Javafx-css-demo-app
javafx-css-demo-app
└ CSSDemoApplication.java
└ MainWindow.java
└ demo.css
└ javafx_account_example.png
12
JavaFX- CSS : Exemplo
13
Resumindo
▸ Os nomes das propriedades CSS dos componentes Java FX são iguais aos de uma
14