Programação Orientada por Objectos (POO)

Propaganda
Programação Orientada por Objectos (POO)
Semestre de Verão de 2009-2010
1º Trabalho prático
Data de Entrega: 19 de Abril de 2010
OBJECTIVOS: Exprimir objectivos na forma de algoritmos recursivos. Completar e desenvolver aplicações simples
usando o paradigma da Programação Orientada por Objectos.
NOTA: No relatório têm que constar todos os programas de teste que lhe permitiram validar a correcção dos métodos e
classes realizadas.
1º Grupo
Complete as seguintes frases:
a) Algoritmos ____________ usam ciclos e se necessário estruturas de dados adicionais. Algoritmos ____________
invocam-se a si próprios até que certa condição seja satisfeita.
b) Para verificar se um elemento existe num array ordenado deve-se usar o algoritmo de pesquisa ____________.
Responda de forma sucinta às seguintes questões:
a) Num algoritmo recursivo quando a chamada recursiva aparece no final, dá-se o nome de recursividade terminal
ou final. Neste caso a última chamada recursiva pode ser transformada num ciclo. Como?
b) Existe alguma relação entre stack overflow e recursão infinita?
c) Quais os cuidados a ter nos algoritmos recursivos para que a recursão seja finita.
Análise e implementação:
1. Indique, justificando, o resultado da execução de main e dê nomes sugestivos ao método e aos parâmetros.
public static void xpto( String s, int x, int y ) {
if ( x >= y ) xpto(s, x / y, y);
System.out.print( s.charAt( x % y) );
}
public static void main( String[] args) { xpto("01", 5, 2)); }
2. Realize um método com a seguinte assinatura, utilizando um algoritmo recursivo:
String getCapicua( int n1, int n2 ),
que recebe dois valores inteiros compreendidos entre 1 e 9, e retorne uma string com os valores de n1 a n2, seguidos
dos valores de (n2-1) a n1. Exemplos de utilização:
System.out.println( getCapicua( 1, 1 ) );
System.out.println( getCapicua( 1, 2 ) );
System.out.println( getCapicua( 3, 9 ) );
1
121
3456789876543
3. Realize um método com a seguinte assinatura, utilizando um algoritmo recursivo:
public static int countBits1( int n )
que recebe um inteiro positivo n e retorna o número de bits a 1 da representação em binário do valor inteiro positivo
n. Exemplos de utilização:
31
System.out.println( countBits1( 0x7FFFFFFF ) );
2
System.out.println( countBits1( 011 ) );
4. Realize um método com a seguinte assinatura, utilizando um algoritmo recursivo:
int[] findSum( int[] sortedArray, int sum )
que, dado o array ordenado de forma estritamente crescente sortedArray e o inteiro sum, retorna dois elementos
desse array tal que a soma seja igual a sum. Esses dois elementos são retornados através de um array com duas
posições. Caso não existam dois elementos cuja soma seja sum, deve ser retornado null.
2º Grupo
1. Pretende-se implementar uma solução para representar sequências de valores inteiros. Para o efeito chegou-se ao
seguinte diagrama de classes:
public class Sequence {
private int currentIndex = 0;
public final int getCurrentIndex() { return currentIndex;
}
public void advance()
{ if (hasElement()) ++ currentIndex;}
public boolean hasElement()
{ return currentIndex < getSize(); }
public int currentElement()
{ return 0; }
public int getSize()
{ return 0; }
}
public class FixedSize extends Sequence {
private final int size;
public FixedSize( int sz )
{ size = sz;
}
public final int getSize()
{ return size; }
}
public class InfiniteSequence extends Sequence {
public final boolean hasElement() { return true; }
public final int getSize()
{ return -1; }
}
A classe Sequence contém as operações comuns a todas as sequências. Uma sequência caracteriza-se pelos valores
que a compõem, obtidos usando os métodos currentElement (que devolve o elemento actual), hasElement
(verifica se foi atingido o final da sequência) e advance (avança para o próximo elemento, caso exista). O método
getCurrentIndex devolve o número de ordem do elemento actual da sequência. O método getSize devolve o
número de inteiros que compõem a sequência, caso seja finita, caso contrário retorna -1.
A classe FixedSize é a classe base de todas as instâncias que representam sequências de n inteiros.
A classe InfiniteSequence é a classe base de todas as instâncias que representam sequências infinitas.
Tendo em consideração o diagrama de classes e a definição das classes Sequence, FixedSize e
InfiniteSequence:
Defina a classe EvenNumbers cujas instâncias representam sequências de n inteiros pares consecutivos a
partir de um dado valor. No construtor são passados o número de inteiros da sequência e o limite inferior.
Como exemplo considere o seguinte troço de código que produz o output: “0:2 – 1:4 – 2:6 – 3:8 –”.
for ( Sequence s = new EvenNumbers(4, 1) ; s.hasElement() ; s.advance() )
if ( s.currentElement() != s.currentElement() )
System.out.print( "ERRO DE IMPLEMENTAÇÃO" );
else System.out.print( s.getCurrentIndex() + ":" + s.currentElement() + " – " );
Defina a classe SortArray cujas instâncias representam sequências de n inteiros ordenados de forma
estritamente crescente contidos na parte do array definida pelos índices de bI (inclusivo) até eI (exclusivo).
Como exemplo considere o seguinte troço de código que produz: “ 0:1 – 1:2 – 3:5 – 4:8 – 0:2 – 1:5 –”.
int[] a = {7, 5, 8, 5, 2, 1 };
Sequence s1 = new SortArray(a, 1, 6),
s2 = new SortArray(a, 3, 5);
for (; s1.hasElement(); s1.advance() )
System.out.print( s1.getCurrentIndex() + ":" + s1.currentElement() + " – " );
for (; s2.hasElement() ; s2.advance() )
System.out.print( s2.getCurrentIndex() + ":" + s2.currentElement() + " – " );
Defina a classe RandomNumbers que representa uma sequência infinita pseudo-aleatória de números. A
classe java.util.Random disponibiliza o método de instância nextInt que, sempre que é evocado, gera
aleatoriamente um valor inteiro. O seguinte troço de código deve produzir 10 números aleatórios.
for ( Sequence s = new RandomNumbers(); s.getCurrentIndex() < 10; s.advance() ) {
if ( s.currentElement() != s.currentElement() )
System.out.print( "ERRO DE IMPLEMENTAÇÃO" );
else
System.out.print( s.currentElement() + " " );
}
Defina a classe Composite que representa sequências compostas pela concatenação de sequências.
Acrescente à classe Composite o método add e redefina os métodos herdados de forma a que o troço de
código abaixo apresentado produza o output presente na caixa de texto:
Composite x = new Composite();
x.add( new SortArray( new int[] {4,2}, 0, 2) );
if ( ! x.add( new RandomNumbers() ) )
System.out.println("1 - Não é possível adicionar sequências infinitas");
Composite y = new Composite();
y.add( x );
x.add( new EvenNumbers(3, 12) );
if ( ! x.add( new Sequence() ) )
System.out.println("2 - Não é possível adicionar sequências vazias");
System.out.print( "Lista " + y.getSize() + ": " );
for ( ; y.hasElement() ; y.advance() )
System.out.print( y.getCurrentIndex() + ":" + y.currentElement() + " – " );
1 - Não é possível adicionar sequências infinitas
2 - Não é possível adicionar sequências vazias
Lista 5: 0:2 – 1:4 – 2:12 – 3:14 – 4:16 –
2. Observe o diagrama UML presente na seguinte Figura e considere-o nas alíneas seguintes
Complete as seguintes frases:
a)
Através do diagrama anterior, verifica-se que a classe E _________________ a classe B e _________________
a interface I2.
b)
Podemos afirmar que todos os objectos do tipo B são do tipo ___ mas que nem todos do tipo B são do tipo ___.
c)
O método público print3 pode ser invocado sobre variáveis do tipo ___ enquanto o método __________ pode
ser invocado sobre qualquer dos tipos que constam no diagrama.
d)
A declaração do método __________ na classe C está incorrecta porque ….
e)
Embora não esteja declarado, a classe D tem que ter pelo menos um __________ porque ….
f)
O troço de código I2 i2 = new I2(); origina um erro de... porque ….
g)
O troço de código I1 i1 = new A( 1 ); origina um erro de... porque ….
h)
Assumindo que a classe D tem um construtor sem parâmetros, o troço de código C c = new D(); origina um
erro de... porque ….
i)
O troço de código I2 i2 = new D(); i2.print3(); origina erro de... porque ….
j)
O troço de código A a = new C(); D d = (D)a; d.print3() origina um erro de... porque ….
Responda de forma sucinta às seguintes questões:
a)
A interface I2 podia ser transformada numa classe abstracta?
b)
O construtor da classe A é herdado pelas classes C e D? E pode ser sobrecarregado ou sobreposto?
Defina as classes correspondentes ao diagrama de classes em que o método:
print1 escreve no console output o nome da classe;
print2 invoca primeiro o print1 da classe base e a seguir o print1 da própria classe;
print3 invoca primeiro o print1 da própria classe e a seguir o print1 da classe base.
3. Pretende-se desenvolver uma aplicação que implemente o “Jogo do Adivinha”. Neste jogo, o jogador pensa em
algo (pensamento) e a aplicação, através de uma sequência de perguntas, de resposta sim/não (decisão), tenta
adivinhar em que é que o utilizador estava a pensar. Em http://www.akinator.com/ está disponível uma versão
online deste jogo, com maior complexidade do que aquela que é pedida neste trabalho.
O jogo usa uma árvore de decisão para manter a informação relativa aos pensamentos (elipses na Figura 1) e
decisões (rectângulos na Figura 1). A Figura apresenta um exemplo da árvore de decisão, através da qual é
possível adivinhar quatro animais usando três questões de decisão. Por exemplo, sabe-se que uma Cobra não tem
Patas, é um Réptil e não é uma Ave (elementos com fundo amarelo na figura 1).
Ave ?
root:
SIM
NÃO
Águia
Réptil ?
SIM
Leão
Patas ?
SIM
Lagartixa
NÃO
NÃO
Cobra
Figura 1: Árvore de decisão
a) Defina uma hierarquia de tipos que suporte a representação da Figura 1, e construa a árvore de decisão.
b) Acrescente suporte para:
i.
Apresentar a árvore de decisão
root.show(“Sim”, “Não”);
Resultado (exemplo para a árvore de decisão da Figura 1):
Ave
Sim: Águia
Não: Réptil
Sim: Patas
Sim: Lagartixa
Não: Cobra
Não: Leão
ii.
Obter o número de pensamentos
int nt = root.getNumberOfThoughts();
iii.
// nt = 4
Verificar da existência de determinado pensamento
boolean exists = root.containsThougth(“Cobra”);
iv.
// exists = true
Mostrar as decisões positivas (Sim) relativas a determinado pensamento
cobra.showDecisionPath();
lagartixa.showDecisionPath();
Cobra -> Réptil
Lagartixa -> Patas -> Réptil
c) Implemente a funcionalidade de jogo, de forma a ser possível:
i.
Pedir ao utilizador para pensar em algo e, com uma sequência de perguntas de resposta
Sim/Não, adivinhar em que é que ele pensou.
ii.
No caso de derrota por parte da aplicação (errar na resposta), perguntar em que é que o
utilizador estava a pensar (pensamento) e de forma é que é diferente (decisão), e adicionar essa
informação à árvore existente.
System.out.println(“Pense em algo.”);
Response res = root.guess(kbd); // descobre em que estou a pensar e usa
// kbd, para fazer perguntas ao utilizador
if (res.success()) {
System.out.println(“Acertei :-)”);
res.showDecisionPath();
} else {
System.out.println(“Ups, estava quase!. Afinal não é ” + res.getThought());
System.out.println(“Em que pensaste? ”);
Thought newTh = new Thought(kbd.nextLine());
System.out.println(“O que o diferencia?”);
Decision newDecision = new Decision(kbd.nextLine(), newTh);
res.replaceWithDecision(newDecision);
newTh.showDecisionPath();
}
Exemplo em que o utilizador pensou em ”Cobra”: (texto do utilizador em itálico, sublinhado e negrito)
Pense em algo.
Ave? N
Réptil? S
Patas? S
Pensou em Cobra? S
Acertei :-)
Cobra -> Réptil
Exemplo em que o utilizador pensou em ”Peixe”:
Pense em algo.
Ave? N
Réptil? N
Pensou em Leão? N
Ups, estava quase!. Afinal não é Leão.
Em que pensaste? Peixe
O que o diferencia? Escamas
Peixe -> Escamas
A Figura 2 mostra as alterações à árvore de decisão após adição do pensamento “Peixe” e respectiva
pergunta de decisão “Escamas”. Note que o novo pensamento é sempre colocado no lado “Sim” da
decisão, e que o pensamento anterior é colocado do lado oposto. A nova decisão é colocada na posição do
antigo pensamento (no caso, “Escamas” substituí “Leão”).
Ave ?
root:
Ave ?
root:
SIM
NÃO
SIM
Águia
Águia
Réptil ?
SIM
SIM
Lagartixa
NÃO
Cobra
Réptil ?
NÃO
SIM
Leão
Patas ?
NÃO
Patas ?
SIM
Lagartixa
NÃO
Escamas ?
NÃO
Cobra
SIM
Peixe
NÃO
Leão
Figura 2: Alterações à árvore de decisão após adição do “Peixe”
Bom trabalho
Download