Programação com Objectos/Teste de 2011/01/10: Difference between revisions

From Wiki**3

< Programação com Objectos
No edit summary
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{TOCright}}
#REDIRECT [[ist:Programação com Objectos/Teste de 2011/01/10]]
== Parte 1 (resposta múltipla) ==
 
[[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?
:#doThat pode ser invocado através de referências para I
:#doThat não está definido para B
:#doIt pode ser invocado através de referências para C
:#A implementa I
:#A é uma classe derivada de C
 
'''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?
:#Strategy
:#Bridge
:#Template Method
:#Visitor
:#State
 
'''1.3.''' Em Java, qual das seguintes frases está correcta?
:#todas as classes são derivadas de java.lang.Class
:#uma classe interna não pode ser anónima
:#uma classe anónima pode implementar uma interface
:#java.lang.Object contém os métodos que permitem definir a ordem por omissão entre quaisquer objectos
:#uma classe abstracta pode ser instanciada se definir construtores
 
'''1.4.''' Em Java, um construtor...
:#não pode chamar outros construtores
:#não pode chamar funções static
:#chama sempre o construtor da superclasse
:#não pode ser privado
:#não pode declarar variáveis locais
 
'''1.5.''' Em Java, as classes internas...
:#não podem ser serializáveis (i.e., não podem implementar java.io.Serializable)
:#não podem conter métodos que lancem excepções
:#podem ser instanciadas dentro de qualquer bloco de uma função
:#constituem um mecanismo para uso exclusivo do tratamento de excepções
:#não podem ter métodos públicos
 
'''1.6.''' Em Java, o método equals...
:#não está disponível nas classes da package java.util
:#é utilizado para definir ordem entre as instâncias de uma classe
:#está disponível apenas para classes que implementem  java.io.Serializable
:#permite comparar apenas objectos com outros da mesma classe
:#permite comparar dois objectos de qualquer tipo
 
'''1.7.''' Em Java, a interface java.lang.Comparable ...
:#é implementada pela classe java.lang.Object
:#as instâncias das suas implementações podem ser utilizadas como chaves pela classe java.util.TreeMap
:#uma classe não deve implementá-la se quiser que as suas instâncias sejam serializáveis
:#só é relevante para classes que implementem java.util.List
:#as respostas anteriores estão erradas
 
'''1.8.''' Relativamente aos padrões de desenho State e Strategy...
:#ambos especificam a delegação de acções em objectos usados pelo cliente
:#as estratégias têm de ser fixadas na altura da criação do cliente, mas os estados não
:#são idênticos, mas as classes que implementam as estratégias são em número fixo
:#gerem as dependências de objectos das suas implementações
:#tratam da mesma forma objectos individuais e suas agregações
 
'''1.9.''' O padrão de desenho Decorator...
:#permite adicionar funcionalidade a um objecto sem alterar a sua interface
:#não pode ser aplicado em conjunto com padrão Visitor
:#permite ajustar a interface e o comportamento de um objecto
:#permite aplicar uma operação a uma estrutura de objectos
:#permite estabelecer o esqueleto de um algoritmo
 
'''1.10.''' O padrão de desenho Abstract Factory...
:#representa a construção de uma colecção
:#gerir as dependências de outros objectos relativamente ao estado de um objecto
:#permite abstrair a criação de famílias de objectos para uma aplicação
:#permite tratar famílias de objectos e seus grupos indiscriminadamente
:#permite que o comportamento de um objecto mude quando o seu estado muda
 
== Parte 2 ==
 
'''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.
 
== Chave da Parte 1 ==
 
[[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?
:#<s>doThat pode ser invocado através de referências para I</s>
:#<s>doThat não está definido para B</s>
:#doIt pode ser invocado através de referências para C
:#<s>A implementa I</s>
:#<s>A é uma classe derivada de C</s>
 
'''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?
:#<s>Strategy</s>
:#<s>Bridge</s>
:#Template Method
:#<s>Visitor</s>
:#<s>State</s>
 
'''1.3.''' Em Java, qual das seguintes frases está correcta?
:#<s>todas as classes são derivadas de java.lang.Class</s>
:#<s>uma classe interna não pode ser anónima</s>
:#uma classe anónima pode implementar uma interface
:#<s>java.lang.Object contém os métodos que permitem definir a ordem por omissão entre quaisquer objectos</s>
:#<s>uma classe abstracta pode ser instanciada se definir construtores</s>
 
'''1.4.''' Em Java, um construtor...
:#<s>não pode chamar outros construtores</s>
:#<s>não pode chamar funções static</s>
:#chama sempre o construtor da superclasse
:#<s>não pode ser privado</s>
:#<s>não pode declarar variáveis locais</s>
 
'''1.5.''' Em Java, as classes internas...
:#<s>não podem ser serializáveis (i.e., não podem implementar java.io.Serializable)</s>
:#<s>não podem conter métodos que lancem excepções</s>
:#podem ser instanciadas dentro de qualquer bloco de uma função
:#<s>constituem um mecanismo para uso exclusivo do tratamento de excepções</s>
:#<s>não podem ter métodos públicos</s>
 
'''1.6.''' Em Java, o método equals...
:#<s>não está disponível nas classes da package java.util</s>
:#<s>é utilizado para definir ordem entre as instâncias de uma classe</s>
:#<s>está disponível apenas para classes que implementem  java.io.Serializable</s>
:#<s>permite comparar apenas objectos com outros da mesma classe</s>
:#permite comparar dois objectos de qualquer tipo
 
'''1.7.''' Em Java, a interface java.lang.Comparable ...
:#<s>é implementada pela classe java.lang.Object</s>
:#as instâncias das suas implementações podem ser utilizadas como chaves pela classe java.util.TreeMap
:#<s>uma classe não deve implementá-la se quiser que as suas instâncias sejam serializáveis</s>
:#<s>só é relevante para classes que implementem java.util.List</s>
:#<s>as respostas anteriores estão erradas</s>
 
'''1.8.''' Relativamente aos padrões de desenho State e Strategy...
:#ambos especificam a delegação de acções em objectos usados pelo cliente
:#<s>as estratégias têm de ser fixadas na altura da criação do cliente, mas os estados não</s>
:#<s>são idênticos, mas as classes que implementam as estratégias são em número fixo</s>
:#<s>gerem as dependências de objectos das suas implementações</s>
:#<s>tratam da mesma forma objectos individuais e suas agregações</s>
 
'''1.9.''' O padrão de desenho Decorator...
:#permite adicionar funcionalidade a um objecto sem alterar a sua interface
:#<s>não pode ser aplicado em conjunto com padrão Visitor</s>
:#<s>permite ajustar a interface e o comportamento de um objecto</s>
:#<s>permite aplicar uma operação a uma estrutura de objectos</s>
:#<s>permite estabelecer o esqueleto de um algoritmo</s>
 
'''1.10.''' O padrão de desenho Abstract Factory...
:#<s>representa a construção de uma colecção</s>
:#<s>gerir as dependências de outros objectos relativamente ao estado de um objecto</s>
:#permite abstrair a criação de famílias de objectos para uma aplicação
:#<s>permite tratar famílias de objectos e seus grupos indiscriminadamente</s>
:#<s>permite que o comportamento de um objecto mude quando o seu estado muda</s>
 
== Resolução da Parte 2 ==
 
===2.1. Classes Paramétricas e Polimorfismo  ===
 
Aspectos importantes:
* Definição de uma classe estruturalmente independente do(s) tipo(s) manipulado(s) (os seus parâmetros).
* O polimorfismo implicado pelas relações de herança (inclusão) permite o uso de uma instância de uma subclasse onde se espera uma de uma superclasse. O polimorfismo paramétrico permite a definição de classes concretas que manipulam qualquer tipo (potencialmente com restrições), evitando a definição de relações de herança (dependência) relativamente a um tipo determinado (introduz restrições desnecessárias). Note-se que uma classe paramétrica pode participar em relações de herança/implementação e ser usada polimorficamente (inclusão) como qualquer outra (e.g., List<A> e ArrayList<A>). No entanto, casos como  ArrayList<Animal> e ArrayList<Gato> não estão relacionadas polimorficamente.
 
===2.2. Visitor & Strategy  ===
 
Aspectos importantes:
* Descrição da estrutura e funcionamento do Visitor
* Vantagens e inconvenientes
* Exemplos: geração de código num compilador a partir de uma árvore sintáctica; desenho de uma cena a partir de uma descrição abstracta; cálculo de impostos sobre uma estrutura composta. Em geral, situações em que uma operação a realizar sobre uma estrutura de objectos e suas folhas possa ser generalizada.
* Visitor vs. Strategy: embora ambos os padrões permitam encapsular algoritmos a realizar sobre estruturas "clientes", tanto a estrutura como o modo de funcionamento são diferentes. No Strategy, apesar de ser possível definir múltiplas versões de um algoritmo, não é possível especializar a operação dependendo do tipo específico do objecto.
 
===2.3. Abstract Factory ===
 
Aspectos importantes:
* Descrição da estrutura e funcionamento do Abstract Factory
* Abstract Factory utiliza polimorfismo para permitir o intercâmbio de fábricas sem ser necessário alterar a aplicação cliente
* Exemplo: escola com professores, salas, alunos, etc.: a estrutura da escola é sempre a mesma, mas a parametrização definida pela fábrica altera o funcionamento (por produzir intervenientes diferentes)
 
===2.4. Composite ===
 
Aspectos importantes:
* Estrutura: uma superclasse define o conceito abstracto a manipular. As subclasses, tanto atómicas, como as composições de componentes, são tratadas indistintamente e apresentam a mesma interface. O processamento de uma composição faz-se pelo processamento iterativo dos seus elementos.
* Exemplo: Rebanhos e Ovelhas (relativamente, por exemplo, à operação tosquiar).
 
===2.5.1. Saída do programa===
A\nC\nB\nA\nC\n
 
===2.5.2. Identificação do padrão de desenho utilizado===
 
O padrão utilizado é o State (Ghost).
 
===2.6. Diagrama de classes (UML) ===
 
Esboço do diagrama de classes para o problema apresentado.
 
[[Image:PO-20100121-class.png]]
 
===2.7. Diagrama de sequência (UML)===
 
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).
 
[[Image:PO-20100121-seq.png]]
 
===2.8. Exercício de programação (Apoio Humanitário) ===
 
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>
 
[[category:PO]]
[[category:Ensino]]

Latest revision as of 17:32, 7 November 2018