Line 2: | Line 2: | ||
== Parte 1 (resposta múltipla) == | == Parte 1 (resposta múltipla) == | ||
− | [[Image:UML-teste-po- | + | [[Image:UML-teste-po-20110110.png|frame|right| Figura 1]] |
'''1.1.''' Considere o diagrama UML da figura 1 (à direita). Qual das seguintes afirmações está correcta? | '''1.1.''' Considere o diagrama UML da figura 1 (à direita). Qual das seguintes afirmações está correcta? | ||
:#doThat pode ser invocado através de referências para I | :#doThat pode ser invocado através de referências para I | ||
Line 153: | Line 153: | ||
== Chave da Parte 1 == | == Chave da Parte 1 == | ||
− | [[Image:UML-teste-po- | + | [[Image:UML-teste-po-20110110.png|frame|right| Figura 1]] |
'''1.1.''' Considere o diagrama UML da figura 1 (à direita). Qual das seguintes afirmações está correcta? | '''1.1.''' Considere o diagrama UML da figura 1 (à direita). Qual das seguintes afirmações está correcta? | ||
:#<s>doThat pode ser invocado através de referências para I</s> | :#<s>doThat pode ser invocado através de referências para I</s> |
1.1. Considere o diagrama UML da figura 1 (à direita). Qual das seguintes afirmações está correcta?
1.2. Que padrão de desenho permite especificar numa classe o esqueleto de um algoritmo, deixando para as subclasses a concretização dos seus passos?
1.3. Em Java, qual das seguintes frases está correcta?
1.4. Em Java, um construtor...
1.5. Em Java, as classes internas...
1.6. Em Java, o método equals...
1.7. Em Java, a interface java.lang.Comparable ...
1.8. Relativamente aos padrões de desenho State e Strategy...
1.9. O padrão de desenho Decorator...
1.10. O padrão de desenho Abstract Factory...
2.1. (1.5 val.) Na linguagem Smalltalk, o método subclassResponsibility pode ser invocado por uma superclasse para indicar que a implementação de um determinado método é da responsabilidade de uma subclasse. Desse modo, se for usada uma subclasse que não implemente o método, o programa chama a versão da superclasse e recebe uma notificação da falta durante a execução. Qual é o mecanismo discutido acima e como é disponibilizado na linguagem Java? Diga quais são as suas vantagens relativas.
2.2. (1.5 val.) O mecanismo de herança potencia o desenvolvimento incremental e a reutilização de funcionalidade existente. No entanto, apesar destes aspectos positivos, apresenta algumas limitações. Descreva algumas das limitações do mecanismo de herança (pode particularizar para Java) e em que medida a utilização de arquitecturas como as previstas em alguns padrões de desenho as minimizam.
2.3. (1.5 val.) Descreva o padrão de desenho State e as vantagens da sua utilização. Explique em que medida o mecanismo de polimorfismo de inclusão é importante para a definição e funcionamento da arquitectura prevista pelo padrão. Dê um exemplo de utilização do padrão.
2.4. (1.5 val.) O padrão de desenho Visitor permite abstrair a aplicação de uma operação a uma estrutura de objectos. Diga qual é o princípio de funcionamento do padrão e que vantagens apresenta a sua utilização. Quais são os problemas introduzidos pela utilização do padrão? Dê um exemplo de aplicação.
2.5. Considere o seguinte programa em Java: <java5> public abstract class Shell {
protected Ghost _ghost; protected Shell(Ghost ghost) { _ghost = ghost; System.out.println(getClass().getName()); } public abstract boolean isOperational(); public abstract void powerOn();
}
public class Virtual extends Shell {
public Virtual(Ghost ghost) { super(ghost); } public boolean isOperational() { return _ghost.isHappy(); } public void powerOn() { System.out.println("always on: nothing to do"); }
}
public class Physical extends Shell {
private boolean _poweredOn = false; public Physical(Ghost ghost) { super(ghost); powerOn(); } public boolean isOperational() { return _poweredOn && _ghost.isHappy(); } public void powerOn() { _poweredOn = true; }
}
public class NotReadyException extends Exception {}
public class ShellTester {
public void assertOperational(Shell shell) throws NotReadyException { if (!shell.isOperational()) { throw new NotReadyException(); } }
}
public class Ghost {
String _name; public Ghost(String name) { _name = name; } public boolean isHappy() { return true; /* ghosts are happy */ }
}
public class Application {
public static void main(String args[]) { Shell kusanagi = new Virtual(new Ghost("草薙素子")); Shell batou = new Physical(new Ghost("バトー")); ShellTester tester = new ShellTester(); try { tester.assertOperational(kusanagi); } catch (NotReadyException e) { System.out.println("Kusanagi not ready!"); } try { tester.assertOperational(batou); } catch (NotReadyException e) { System.out.println("Batou not ready!"); } }
} </java5>
2.5.1. (1.0 val.) Que resultado se obtém quando se executa o seguinte programa? (represente mudanças de linha com \n)
2.5.2. (0.5 val.) Que padrão de desenho é usado no programa?
2.5.3. (1.5 val.) Desenhe o diagrama de sequência UML correspondente à execução do programa, incluindo as etapas de criação dos objectos. O diagrama de sequência deve conter os nomes das mensagens trocadas (não é necessário representar os argumentos dessas mensagens nem as de retorno; não é necessário explicitar o construtor de Shell).
2.6. Considere o seguinte domínio:
Uma biblioteca possui livros, CDs, vídeos e jogos. Todas estas obras são identificadas por um número de série, uma data de aquisição e uma descrição de catálogo. Os livros, CDs e vídeos têm ainda a indicação de qual é o título e de quem é o autor. Os vídeos e os jogos têm indicação de qual é a idade mínima para empréstimo. A biblioteca mantém sobre os seus visitantes um registo, no qual inclui (sobre cada um) o nome, a data de nascimento, morada e número de telefone. Quando é realizado um novo registo, o novo utilizador fica sem acesso às obras com idade controlada se a idade for menor que um valor dado (à medida que o tempo passa e o utilizador envelhece, o acesso vai também evoluindo). São definidos três níveis de acesso: infantil (>0), juvenil (>12) e adulto (>18). No caso de utilizadores não adultos, a biblioteca associa ao menor um utilizador adulto, que é responsável pelas obras emprestadas (mantém um registo dedicado às obras emprestadas ao menor). A biblioteca guarda um registo dos empréstimos realizados (obra emprestada, utilizador e datas de empréstimo e limite para entrega). É possível pedir várias obras num único empréstimo e é possível contabilizar, tanto por utilizador, como na totalidade dos utilizadores, o número de obras emprestadas. Se uma obra não estiver disponível, é possível deixar um contacto para notificação em caso de devolução.
2.6.1. (2.0 val.) Desenhe o diagrama de classes UML correspondente ao domínio apresentado. Represente as classes (seus nomes, métodos e atributos). Indique também as relações de herança, associação e agregação.
2.6.2. (4.0 val.) Implemente em Java todas as classes, bem como os seus atributos e métodos, do domínio apresentado. Considere que deve haver flexibilidade na definição do tipo de cliente, na forma de transitar entre tipos de cliente, e no registo de empréstimos.
1.1. Considere o diagrama UML da figura 1 (à direita). Qual das seguintes afirmações está correcta?
1.2. Que padrão de desenho permite especificar numa classe o esqueleto de um algoritmo, deixando para as subclasses a concretização dos seus passos?
1.3. Em Java, qual das seguintes frases está correcta?
1.4. Em Java, um construtor...
1.5. Em Java, as classes internas...
1.6. Em Java, o método equals...
1.7. Em Java, a interface java.lang.Comparable ...
1.8. Relativamente aos padrões de desenho State e Strategy...
1.9. O padrão de desenho Decorator...
1.10. O padrão de desenho Abstract Factory...
Aspectos importantes:
Aspectos importantes:
Aspectos importantes:
Aspectos importantes:
A\nC\nB\nA\nC\n
O padrão utilizado é o State (Ghost).
Esboço do diagrama de classes para o problema apresentado.
Note-se que alguns objectos não indicam variáveis associadas (os resultados da criação desses objectos são imediatamente passados como argumentos de outros métodos).
Usa-se o padrão Visitor como forma de abstrair o cálculo da ajuda prestada.
Definem-se quatro conceitos: o beneficiário abstracto (HelpTarget), e cada um dos concretos (Person, Village, Region).
<java5> /**
* Basic help target. */
public abstract class HelpTarget {
/** * No actual value is returned in this case. * * @param calculator the visitor used to evaluate assistance. * @return help received by this target. */ public double accept(Calculator calculator) { throw new UnsupportedOperationException(); }
} </java5>
<java5> /**
* Individual. * We omitted the initialisation code. */
public class Person extends HelpTarget {
/** * @see HelpTarget#accept(Calculator) */ @Override public double accept(Calculator calculator) { return calculator.evalPerson(this); }
}
</java5>
<java5> import java.util.ArrayList;
/**
* A village has villagers (persons). * We omitted the initialisation code. */
public class Village extends HelpTarget {
/** * The villagers in this village. */ private ArrayList<Person> _villagers = new ArrayList<Person>();
/** * Simple constructor for initialising the village with some villagers. */ public Village() { int count = (int) (Math.random() * 100); for (int i = 0; i < count; i++) _villagers.add(new Person()); }
/** * @return size of village (number of villagers). */ public int size() { return _villagers.size(); }
/** * @param index * @return a villager */ public Person getVillager(int index) { return _villagers.get(index); }
/** * @see HelpTarget#accept(Calculator) */ @Override public double accept(Calculator calculator) { return calculator.evalVillage(this); }
} </java5>
<java5> import java.util.ArrayList;
/**
* A region has villages. * We omitted the initialisation code. */
public class Region extends HelpTarget {
/** * The villages in this region. */ private ArrayList<Village> _villages = new ArrayList<Village>();
/** * Simple constructor for initialising the region with some villages. */ public Region() { int count = (int) (Math.random() * 100); for (int i = 0; i < count; i++) _villages.add(new Village()); }
/** * @return size of region (number of villages). */ public int size() {return _villages.size(); }
/** * @param index * @return a village */ public Village getVillage(int index) { return _villages.get(index); }
/** * @see HelpTarget#accept(Calculator) */ @Override public double accept(Calculator calculator) { return calculator.evalRegion(this); }
} </java5>
A classe Calculator define a interface de cálculo para cada conceito. <java5> /**
* The Calculator visitor interface. */
public abstract class Calculator {
/** * @param person * @return help received by this person. */ public abstract double evalPerson(Person person);
/** * @param village * @return help received by this village. */ public abstract double evalVillage(Village village);
/** * @param region * @return help received by this region. */ public abstract double evalRegion(Region region);
} </java5>
O processo de cálculo simples é definido pela classe Standard.
<java5> /**
* "Standard" help calculator. */
public class Standard extends Calculator {
/** * @see Calculator#evalVillage(Village) */ @Override public double evalVillage(Village village) { double tax = 0; for (int index = 0; index < village.size(); index++) tax += village.getVillager(index).accept(this); return tax; }
/** * @see Calculator#evalPerson(Person) */ @Override public double evalPerson(Person person) { return 1; }
/** * @see Calculator#evalRegion(Region) */ @Override public double evalRegion(Region region) { double tax = 0; for (int index = 0; index < region.size(); index++) tax += region.getVillage(index).accept(this); return tax; }
} </java5>
O processo de cálculo para emergências é definido pela classe Emergency.
<java5> /**
* The emergency help system. */
public class Emergency extends Calculator {
/** * High-water marker for region occupation. */ private final int REGION_MAX = 20;
/** * High-water marker for population. */ private final int VILLAGE_MAX = 100;
/** * @see Calculator#evalVillage(Village) */ @Override public double evalVillage(Village village) { double help = 0; for (int index = 0; index < village.size(); index++) help += village.getVillager(index).accept(this); if (village.size() > VILLAGE_MAX) help *= .75; return help; } /** * @see Calculator#evalPerson(Person) */ @Override public double evalPerson(Person person) { return 1; } /** * @see Calculator#evalRegion(Region) */ @Override public double evalRegion(Region region) { double help = 0; for (int index = 0; index < region.size(); index++) help += region.getVillage(index).accept(this); if (region.size() > REGION_MAX) help *= .9; return help; }
} </java5>
Simple aoolication.
<java5> public class App {
/** * @param args */ public static void main(String[] args) { HelpTarget v1 = new Village(); HelpTarget r1 = new Region(); HelpTarget p1 = new Person(); Calculator sh = new Standard(); Calculator eh = new Emergency(); System.out.println("Village help (standard): " + v1.accept(sh)); System.out.println("Region taxes (standard): " + r1.accept(sh)); System.out.println("Person taxes (standard): " + p1.accept(sh)); System.out.println("Village taxes (emergency): " + v1.accept(eh)); System.out.println("Region taxes (emergency): " + r1.accept(eh)); System.out.println("Person taxes (emergency): " + p1.accept(eh)); }
} </java5>