Programação com Objectos/Teste de 2012/01/07

From Wiki**3

< Programação com Objectos

Parte 1

1.1. (1.5 val.) Os mecanismos de herança entre classes e de composição de objectos são, por vezes, apresentados como alternativos, face à disponibilização de funcionalidade ao código de uma classe. Compare-os, em termos de potencialidade e flexibilidade. Contraste as diferenças e vantagens relativas no contexto da aplicação do padrão de desenho Strategy.

Pontos importantes: herança permite reutilização e "pré-definição" de comportamento, mas é inflexível e alterações no topo da hierarquia propagam-se inexoravelmente para os níveis inferiores. Strategy permite definição de comportamento por composição (não confundir com uso do padrão Composite), que apresenta maior flexibilidade (podendo ser inclusivamente alterado em tempo de execução).

1.2. (1.5 val.) Relacione o mecanismo de herança e o conceito de polimorfismo e diga de que forma potenciam o desenvolvimento incremental e evitam a repetição de código. Na discussão, foque os aspectos positivos e possíveis limitações. Que conceitos estão disponíveis em Java para realizar aqueles mecanismos? Ilustre com um exemplo.

  • Herança: permite a abstracção de características comuns
  • Herança: permite escrita de código em função de conceitos gerais (este código pode vir a ser reutilizado em especializações do conceito)
  • Polimorfismo (especialmente de inclusão): permite que o código escrito para tratar objectos de um tipo venha a ser utilizado para processar objectos de tipos derivados
  • Java: classes e interfaces, herança de classes (extends), implementação de interfaces (implements)
  • Java (conceitos relacionados): redefinição de métodos (overriding)

1.3. (1.5 val.) Tanto o padrão de desenho State como o padrão de desenho Strategy se baseiam na delegação de comportamento por parte do cliente nas instâncias de classes previstas pelo padrão (respectivamente, o estado e a estratégia). Discuta as semelhanças e as diferenças entre os dois padrões, tanto em termos da arquitectura prevista, como da intenção e das consequências da utilização de cada padrão. Apresente exemplos ilustrativos.

Aspectos importantes:

  • Descrição comparativa das estruturas correspondentes
  • Descrição comparativa do funcionamento
  • Implicações, em termos de impacto para o cliente e acções por parte do cliente

1.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.

Aspectos importantes:

  • Descrição da estrutura e funcionamento do Visitor
  • Princípio de funcionamento (double dispatching): os objectos da estrutura de dados implementam um método (accept) que recebe qualquer visitante (polimorfismo); nesse método, é invocado sobre visitante o método que tem como argumento o objecto visitado (e que todos os visitantes têm de implementar).
  • Vantagens: é possível associar funcionalidade adicional a objectos sem necessidade de alterar as suas classes (a funcionalidade é específica para cada objecto visitado)
  • Desvantagens: devido ao número de métodos a implementar, pode não ser conveniente utilizar esta arquitectura, especialmente se não houver necessidade de ampliar a funcionalidade a associar aos objectos (o número total de métodos a manter é o produto do número de visitados pelo número de visitantes); a adição de um novo tipo de objecto ao conjunto dos visitados obriga à escrita de um novo método em todos os visitantes.
  • 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.

1.5. Considere o seguinte programa em Java: <java5> public class Chicken {

 private Stomach _stomach = new Hungry(this);

  public void eat() { _stomach.eat(); }   public void sleep() { _stomach.sleep(); }   public void setStomach(Stomach stomach) { _stomach = stomach; } }

public abstract class Stomach {   protected Chicken _chicken;   protected Stomach(Chicken chicken) { _chicken = chicken; }   public void eat() { System.out.println("..."); }   public void sleep() { System.out.println("..."); } }

public class Hungry extends Stomach {   public Hungry(Chicken chicken) {     super(chicken);     System.out.println("I'm hungry!!");   }

  public void eat() {     System.out.println("Eating...");     _chicken.setStomach(new Sated(_chicken));   }     public void sleep() { System.out.println("I'm too hungry to sleep!!"); } }

public class Sated extends Stomach {   public Sated(Chicken chicken) {     super(chicken);     System.out.println("I'm sleepy!!");   }     public void sleep() {     System.out.println("ZzZz...");     _chicken.setStomach(new Hungry(_chicken));   }

}

public class Farm {

 public static void main(String args[]) {
   Chicken chicken = new Chicken();
   chicken.eat();
   chicken.sleep();
   chicken.sleep();
 }

} </java5>

1.5.1. (1.0 val.) Que resultado se obtém quando se executa o seguinte programa? (represente mudanças de linha com \n)

I'm hungry!!\nEating...\nI'm sleepy!!\nZzZz...\nI'm hungry!!\nI'm too hungry to sleep!!\n

1.5.2. (0.5 val.) Que padrão de desenho é usado no programa?

State 

1.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; represente todas as chamadas ao método println).

Note-se que alguns objectos (anotados) não definem as variáveis associadas no momento indicado.

PO-20120107-seq.png

1.6. Considere o seguinte domínio:

Uma editora gere vários tipos de publicação (livros, revistas e tablóides), cada um composto por várias peças (artigos, fotografias e publicidade). Podem ser criados mais tipos, tanto de publicação, como de peça. Nem todos os tipos de peça se podem incluir todas em todas as publicações: nos livros, apenas são incluídos artigos; nas revistas, podem ser inseridos artigos e fotografias; nos tablóides, todas as peças podem aparecer. Todas as publicações e peças são identificadas por um número inteiro. As publicações e peças têm ainda a indicação de qual é o título e de quem é o autor. A editora mantém sobre os seus autores um registo, no qual inclui (sobre cada um) o nome e o número de telefone.

A forma de disponibilização de publicações, i.e., papel, web, meios móveis, etc., permite oferecer variedade ao consumidor, mas complica a definição de uma arquitectura flexível para a aplicação. Inicialmente, estão definidos dois formatos: textual e estruturado. No formato textual, os atributos das publicações são apresentados sucessivamente e as peças e seus atributos são também simplesmente apresentados de forma textual simples (as fotografias são representadas pelo seu título). No formato estruturado, em XML, cada publicação é iniciada e terminada por uma “tag” que a caracteriza (respectivamente, <book>, <magazine>, etc. e </book>, etc.), o mesmo se passando com as peças. Os atributos são apresentados como atributos XML (e.g., para o autor de um livro: <book author="anónimo">). Os elementos internos são ancorados dentro dos externos, como é habitual em XML. A solução de apresentação deve permitir flexibilidade na definição de novas formas de apresentação sem impacto no código existente.

1.6.1. (2.0 val.) Desenhe o diagrama de classes UML correspondente ao domínio apresentado. Represente todas as classes (seus nomes, métodos e atributos). Indique também as relações de herança, associação e agregação.

Esboço do diagrama de classes para o problema apresentado.

PO-20120107-class.png

1.6.2. (4.0 val.) Implemente em Java todas as classes do domínio apresentado, bem como os seus atributos e métodos (excepto getters e setters). Os atributos identificados devem ser suficientes para suportar a funcionalidade e os métodos devem conter implementações que permitam verificar inequivocamente que a funcionalidade desejada (especialmente a que diz respeito às relações entre objectos) está correcta. Não implemente o código correspondente à apresentação sob a forma textual simples.

<java5> // Author.java public class Author {

       protected String _name;
       protected String _phone;
       public Author(String name, String phone) {
               _name = name;
               _phone = phone;
       }
       public String getName() {
               return _name;
       }
       public String getPhone() {
               return _phone;
       }

} </java5>

<java5> // Formattable.java public interface Formattable {

       String accept(Formatter formatter);

} </java5>

<java5> // BookItem.java public interface BookItem extends Formattable {} </java5>

<java5> // MagazineItem.java public interface MagazineItem extends Formattable {} </java5>

<java5> // TabloidItem.java public interface TabloidItem extends Formattable {} </java5>

<java5> // Publication.java public abstract class Publication implements Formattable {

       private int _id;
       private Author _author;
       private String _title;
       public Publication(int id, Author author, String title) {
               _id = id;
               _author = author;
               _title = title;
       }
       public int getId() {
               return _id;
       }
       public Author getAuthor() {
               return _author;
       }
       public String getTitle() {
               return _title;
       }

} </java5>

<java5> // Book.java import java.util.List; import java.util.ArrayList;

public class Book extends Publication {

       private List<BookItem> _items = new ArrayList<BookItem>();
       public Book(int id, Author author, String title) {
               super(id, author, title);
       }
       public void add(BookItem item) {
               _items.add(item);
       }
       public String accept(Formatter formatter) {
               return formatter.formatBook(this);
       }
       public List<BookItem> getItems() {
               return _items;
       }

} </java5>

<java5> // Magazine.java import java.util.List; import java.util.ArrayList;

public class Magazine extends Publication {

       private List<MagazineItem> _items = new ArrayList<MagazineItem>();
       public Magazine(int id, Author author, String title) {
               super(id, author, title);
       }
       public void add(MagazineItem item) {
               _items.add(item);
       }
       public String accept(Formatter formatter) {
               return formatter.formatMagazine(this);
       }
       public List<MagazineItem> getItems() {
               return _items;
       }

} </java5>

<java5> // Tabloid.java import java.util.List; import java.util.ArrayList;

public class Tabloid extends Publication {

       private List<TabloidItem> _items = new ArrayList<TabloidItem>();
       public Tabloid(int id, Author author, String title) {
               super(id, author, title);
       }
       public void add(TabloidItem item) {
               _items.add(item);
       }
       public String accept(Formatter formatter) {
               return formatter.formatTabloid(this);
       }
       public List<TabloidItem> getItems() {
               return _items;
       }

} </java5>

<java5> // Item.java abstract class Item implements TabloidItem, Formattable {

       private int _id;
       private Author _author;
       private String _title;
       public Item(int id, Author author, String title) {
               _id = id;
               _author = author;
       }
       public int getId() {
               return _id;
       }
       public Author getAuthor() {
               return _author;
       }
       public String getTitle() {
               return _title;
       }

} </java5>

<java5> // Advertisement.java public class Advertisement extends Item {

       public Advertisement(int id, Author author, String title) {
               super(id, author, title);
       }
       public String accept(Formatter formatter) {
               return formatter.formatAdvertisement(this);
       }

} </java5>

<java5> // Article.java public class Article extends Item implements BookItem, MagazineItem {

       public Article(int id, Author author, String title) {
               super(id, author, title);
       }
       public String accept(Formatter formatter) {
               return formatter.formatArticle(this);
       }

} </java5>

<java5> // Image.java public class Image extends Item implements MagazineItem {

       public Image(int id, Author author, String title) {
               super(id, author, title);
       }
       public String accept(Formatter formatter) {
               return formatter.formatImage(this);
       }

} </java5>

<java5> // Publisher.java import java.util.Map; import java.util.TreeMap;

public class Publisher {

       private Map<String, Author> _authors = new TreeMap<String, Author>();
       private Map<Integer, Publication> _publications = new TreeMap<Integer, Publication>();
       public void add(Author author) {
               _authors.put(author.getName(), author);
       }
       public void add(Publication publication) {
               Author author = publication.getAuthor();
               if (author != null)
                       _authors.put(author.getName(), author);
               _publications.put(publication.getId(), publication);
       }
       public String formatPublication(int id, Formatter formatter) {
               Publication publication = _publications.get(id);
               if (publication != null)
                       return publication.accept(formatter);
               return "";
       }
       public String formatPublications(Formatter formatter) {
               String rendering = "";
               for (Publication publication : _publications.values())
                       rendering += publication.accept(formatter) + "\n";
               return rendering;
       }

} </java5>

<java5> // Formatter.java public interface Formatter {

       String formatBook(Book book);
       String formatMagazine(Magazine magazine);
       String formatTabloid(Tabloid tablid);
       String formatArticle(Article article);
       String formatImage(Image image);
       String formatAdvertisement(Advertisement advertisement);

} </java5>

<java5> // TextFormatter.java // TO DO </java5>

<java5> // StructuredFormatter.java public class StructuredFormatter implements Formatter {

       public String formatBook(Book book) {
               Author author = book.getAuthor();
               String rendering = "<book author='" + author.getName() + "' id='" + book.getId() + "'>\n";
               for (BookItem item : book.getItems())
                       rendering += item.accept(this);
               return rendering + "</book>" + "\n";
       }
       public String formatMagazine(Magazine magazine) {
               Author author = magazine.getAuthor();
               String rendering = "<magazine author='" + author.getName() + "' id='" + magazine.getId() + "'>\n";
               for (MagazineItem item : magazine.getItems())
                       rendering += item.accept(this);
               return rendering + "</magazine>" + "\n";
       }
       public String formatTabloid(Tabloid tabloid) {
               Author author = tabloid.getAuthor();
               String rendering = "<tabloid author='" + author.getName() + "' id='" + tabloid.getId() + "'>\n";
               for (TabloidItem item : tabloid.getItems())
                       rendering += item.accept(this);
               return rendering + "</tabloid>" + "\n";
       }
       public String formatArticle(Article article) {
               Author author = article.getAuthor();
               String rendering = "  <article author='" + author.getName() + "' id='" + article.getId() + "'>\n";
               return rendering + "    \n" + "  </article>\n";
       }
       public String formatImage(Image image) {
               Author author = image.getAuthor();
               String rendering = "  <image author='" + author.getName() + "' id='" + image.getId() + "'>\n";
               return rendering + "    \n" + "  </image>\n";
       }
       public String formatAdvertisement(Advertisement advertisement) {
               Author author = advertisement.getAuthor();
               String rendering = "  <advertisement author='" + author.getName() + "' id='" + advertisement.getId() + "'>\n";
               return rendering + "    \n" + "  </advertisement>\n";
       }

} </java5>

<java5> // Application.java // not part of official answer public class Application {

       public static void main(String[] args) {
               Publisher publisher = new Publisher();
               Author jane = new Author("Jane Austen", "02-993-15");
               Author homer = new Author("Homer", "(send runner)");
               Author blabla = new Author("B.L.A.", "+351-123-456-789");
               Author bbq = new Author("B.B.Q.", "none");
               Author bnl = new Author("Buy'n'Large", "none");
               Item ad1 = new Advertisement(1, bbq, "Buy now!");
               Item ad2 = new Advertisement(2, bnl, "The Axiom! Travel in style!");
               Article a1 = new Article(4, jane, "Unpublished Chapter 2");
               Article a2 = new Article(6, jane, "Unpublished Chapter 6");
               Article a3 = new Article(8, homer, "Odysseus Unleashed");
               Image i1 = new Image(5, homer, "Troy in flames");
               Book b1 = new Book(56, jane, "Unpublished");
               b1.add(a1);
               b1.add(a2);
               Book b2 = new Book(73, homer, "Stories");
               b2.add(a3);
               Magazine m1 = new Magazine(25, blabla, "Events Today");
               m1.add(a3);
               m1.add(i1);
               Tabloid t1 = new Tabloid(86, bnl, "The Things They Do!!!");
               t1.add(ad1);
               t1.add(a3);
               t1.add(i1);
               t1.add(ad2);
               t1.add(a1);
               t1.add(ad1);
               publisher.add(b1);
               publisher.add(b2);
               publisher.add(m1);
               publisher.add(t1);
               String txtPrintable = publisher.formatPublications(new TextFormatter());
               String xmlPrintable = publisher.formatPublications(new StructuredFormatter());
               System.out.println(xmlPrintable);
       }

} </java5>

<text> <magazine author='B.L.A.' id='25'>

 <article author='Homer' id='8'>
 </article>
 <image author='Homer' id='5'>
 </image>

</magazine>

<book author='Jane Austen' id='56'>

 <article author='Jane Austen' id='4'>
 </article>
 <article author='Jane Austen' id='6'>
 </article>

</book>

<book author='Homer' id='73'>

 <article author='Homer' id='8'>
 </article>

</book>

<tabloid author='Buy'n'Large' id='86'>

 <advertisement author='B.B.Q.' id='1'>
 </advertisement>
 <article author='Homer' id='8'>
 </article>
 <image author='Homer' id='5'>
 </image>
 <advertisement author='Buy'n'Large' id='2'>
 </advertisement>
 <article author='Jane Austen' id='4'>
 </article>
 <advertisement author='B.B.Q.' id='1'>
 </advertisement>

</tabloid> </text>

Parte 2 (resposta múltipla)

UML-teste-po-20120107.png
2.1. Considere o diagrama UML da figura 1 (à direita). Qual das seguintes afirmações está correcta?
  1. a implementação de doThat tem de estar necessariamente em A
  2. doThat não está definido para B
  3. doIt pode ser directamente invocado através de referências para I
  4. A fornece a implementação para métodos declarados por I
  5. A é uma classe derivada de B

2.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. Strategy
  2. Adapter
  3. Visitor
  4. Template Method
  5. Command

2.3. O padrão de desenho Adapter...

  1. permite ajustar a interface e o comportamento de um objecto
  2. permite adicionar funcionalidade a um objecto adaptando a sua interface
  3. não pode ser aplicado em conjunto com padrão Template Method
  4. permite aplicar uma operação a uma estrutura de objectos
  5. permite estabelecer o esqueleto de um algoritmo

2.4. O padrão de desenho Observer...

  1. representa a construção de uma colecção
  2. gerir as dependências de outros objectos relativamente ao estado de um objecto
  3. permite abstrair a criação de famílias de objectos para uma aplicação
  4. permite tratar famílias de objectos e seus grupos indiscriminadamente
  5. permite que o comportamento de um objecto mude quando o seu estado muda

2.5. Relativamente ao padrão de desenho Decorator...

  1. é possível adicionar, no decorador, comportamento adicional, desde que a interface original seja mantida
  2. não é possível adicionar, no decorador, comportamento adicional, mesmo que a interface original seja mantida
  3. a interface original só é mantida se não for adicionado comportamento adicional
  4. a adição de comportamento adicional condiciona a redefinição da interface
  5. o ajuste da interface é realizado pelo comportamento adicional

2.6. Em Java, qual das seguintes frases está correcta?

  1. uma classe interna não pode ser anónima
  2. uma excepção pode ser apanhada e relançada
  3. uma classe anónima não pode implementar uma interface
  4. os métodos de classes anónimas não podem lançar excepções
  5. uma classe abstracta pode ser instanciada se definir pelo menos um construtor

2.7. Em Java, um método declarado private...

  1. não pode chamar outros métodos
  2. não pode ser redefinido
  3. não pode ser declarado static
  4. não pode ser usado por construtores
  5. pode ser acedido por classes da mesma package

2.8. Em Java, o mecanismo de redefinição de métodos...

  1. não pode ser utilizado por classes anónimas
  2. permite redefinir numa subclasse qualquer método de uma superclasse
  3. funciona apenas se os métodos não forem declarados static
  4. não funciona para métodos públicos
  5. nenhuma das anteriores

2.9. Em Java, a utilização da palavra protected...

  1. indica que apenas as classes da mesma package podem aceder ao membro da classe em causa
  2. permite definir um atributo como sendo constante
  3. permite acesso aos membros da classe assim declarados, por parte de classes dela derivadas, definidas em outras packages
  4. permite garantir que um método assim declarado não altera o objecto sobre o qual é chamado
  5. impede o acesso aos membros assim declarados (i.e., apenas a própria classe lhes tem acesso)

2.10. Em Java, a interface java.lang.Comparable...

  1. é implementada pela classe java.lang.Object
  2. permite verificar a igualdade entre dois objectos de quaisquer tipos
  3. não deve ser implementada por classes cujas instâncias sejam armazenadas em mapas do tipo java.lang.TreeMap
  4. permite usar o método Collections.sort sobre uma lista que contenha instâncias de uma classe que a implementa
  5. deve ser implementada por classes cujas instâncias sejam armazenadas em mapas do tipo java.lang.HashMap