Ybadoo - Soluções em Software Livre
Turmas
2º Semestre de 2015

Questão 01

Não existe uma definição universalmente aceita de padrão, mas talvez o melhor seja começar por Cristopher Alexander, uma inspiração para muitos entusiastas de padrões: "Cada padrão descreve um problema que ocorre repetidamente no nosso ambiente e então descreve a essência da solução desse problema, de tal forma que você possa usar essa solução um milhão de vezes, sem jamais fazê-lo exatamente da mesma forma". Alguns elementos que compõem um padrão são:

  1. O nome do padrão expressa a sua própria essência de forma sucinta.
  2. A motivação é um cenário que ilustra um problema de projeto e como as estruturas de classes e objetos no padrão solucionam o problema.
  3. Os participantes são as classes e/ou objetos que participam do padrão de projeto e suas responsabilidades.
  4. As consequências são os resultados e análises das vantagens e desvantagens (trades-offs) da aplicação do padrão.

Em geral, um padrão tem quatro elementos essenciais, apresentados em:

  1. I.
  2. II.
  3. I e IV.
  4. II e III.
  5. III e IV.

Questão 02

A interface com o usuário de muitos programas fornecem várias formas de executar um determinado comando. Por exemplo, para recortar um bloco de texto em um editor de textos, podemos selecionar EditarRecortar a partir do menu, clicar no botão da barra de ferramentas com o ícone de uma tesoura ou simplesmente digitar a combinação de teclas CTRL+X. Isso, naturalmente, é fácil de implementar. Simplesmente associamos os tratadores dos eventos do menu, da barra de ferramentas e do teclado ao código que executa a operação "recortar". Mas um comando desses faz mais do que simplesmente executar a operação desejada. Por exemplo, se não há nada para recortar, então o botão da barra de ferramentas deve ser desabilitado. Um item de menu ou botão desabilitado tem uma aparência visual diferente. Também é útil que o comando "recortar" possa lembrar se está habilitado ou não. Dessa forma, um comando tem tanto um comportamento como um estado. Qual padrão de projeto resolve esse problema?

  1. Chain of Responsibility − evita o acoplamento do remetente de uma solicitação ao seu destinatário, dando a mais de um objeto a chance de tratar a solicitação. Encadeia os objetos receptores e passa a solicitação ao longo da cadeia até que um objeto a trate.
  2. Command − encapsular uma solicitação como um objeto, desta forma permitindo parametrizar clientes com diferentes solicitações, enfileirar ou fazer o registro (log) de solicitações e suportar operações que podem ser desfeitas.
  3. Memento − sem violar a encapsulação, captura e externaliza um estado interno de um objeto, de modo que o mesmo possa posteriormente ser restaurado para este estado.
  4. Observer − define uma dependência um-para-muitos entre objetos, de modo que, quando um objeto muda de estado, todos os seus dependentes são automaticamente notificados e atualizados.
  5. State − permite a um objeto alterar seu comportamento quando o seu estado interno se altera, parecendo que o objeto alterou sua classe.

Questão 03

Objetos compostos normalmente têm estruturas complexas, constituídas de elementos individuais. Alguns elementos podem, por sua vez, ter elementos filhos. Estes elementos podem pertencer a várias classes. Uma operação sobre um elemento visita seus filhos, aplica operações sobre eles e combina os resultados. Um exemplo é um contêiner de interface com o usuário que é constituído por componentes, alguns contendo componentes adicionais. As classes Component e Container do pacote java.awt contêm várias operações tais como getPreferredSize e repaint, que são aplicadas recursivamente sobre os elementos filhos. Entretanto, não é fácil acrescentar novas operações neste projeto. Suponha que você deseje suportar uma nova operação para contêineres e componentes de interface com o usuário. Essa operação teria de ser acrescentada na classe Component e em várias subclasses. Só que o programador de aplicação não pode acrescentar métodos em classes de bibliotecas. Qual padrão de projeto ensina como o projetista de uma biblioteca pode fornecer um mecanismo extensível para resolver esse problema:

  1. Composite − compõem objetos em estrutura de árvore para representar hierarquias do tipo partes-todo. O Composite permite que os clientes tratem objetos individuais e composições de objetos de maneira uniforme.
  2. Decorator − atribui responsabilidades adicionais a um objeto dinamicamente. Os decorators fornecem uma alternativa flexível a subclasses para extensão da funcionalidade.
  3. Strategy − define uma família de algoritmos, encapsular cada um deles e fazê-los intercambiáveis. O Strategy permite que o algoritmo varie independentemente dos clientes que o utilizem.
  4. Template Method − define o esqueleto de um algoritmo em uma operação, postergando a definição de alguns passos para subclasses. O Template Method permite que as subclasses redefinem certos passos de um algoritmo sem mudar sua estrutura.
  5. Visitor − representa uma operação a ser executada sobre os elementos da estrutura de um objeto. O Visitor permite que você defina uma nova operação sem mudar as classes dos elementos sobre os quais opera.

Quando uma abstração pode ter uma entre várias implementações possíveis, a maneira usual de acomodá-las é usando a herança. Uma classe abstrata define a interface para a abstração, e subclasses concretas a implementam de formas diferentes. Mas essa abordagem nem sempre é suficientemente flexível. A herança liga uma implementação à abstração permanentemente, o que torna difícil modificar, aumentar e reutilizar abstrações e implementações independentemente.

Considere a implementação de um sistema estatístico que permita ao usuário selecionar o método a ser utilizado para o calculo da média de uma série de números, que podem ser fornecidos pelo usuário por meio de um vetor, uma matriz, uma lista dentre diversas outras formas.

O código a seguir apresenta a forma como o usuário vai utilizar as chamadas aos métodos estatísticos empregados.

Application.java

Integer[] values = {1, 2, 3, 4, 5};

Element vector = new ElementVector(values, new ArithmeticMean());
System.out.println(vector.getMean());

vector = new ElementVector(values, new HarmonicMean());
System.out.println(vector.getMean());

List<Integer> listValues = new ArrayList<>();
listValues.add(1);
listValues.add(2);
listValues.add(3);
listValues.add(4);
listValues.add(5);
    
Element list = new ElementList(listValues, new ArithmeticMean());
System.out.println(list.getMean());
    
list = new ElementList(listValues, new GeometricMean());
System.out.println(list.getMean());
  1. Qual o padrão de projeto mais adequado para ser usado no desenvolvimento deste sistema?
  2. Apresente o diagrama de classes em UML da solução proposta.
  3. Apresente a codificação na linguagem de programação Java das classes ElementVector e ArithmeticMean.

Questão Extra

Dado o código a seguir:

Arquivo MyThread.java

public class MyThread extends Thread
{
  public MyThread()
  {
    System.out.print("MyThread ");
  }
  
  public void run()
  {
    super.run();
    
    System.out.print("run ");
  }
  
  public void start()
  {
    super.start();
    
    System.out.print("start ");
  }
}

Arquivo TestThreads.java

public class TestThreads
{
  public TestThreads()
  {
    System.out.print("TestThreads ");
  }
  
  public static void main(String[] args)
  {
    Thread t = new MyThread();
    
    t.start();
  }
}

Qual será o resultado impresso após a execução do programa apresentado:

  1. MyThread start
  2. MyThread run start
  3. TestThreads MyThread start
  4. MyThread start run
  5. MyThread run