Ybadoo - Soluções em Software Livre
Turmas
1º Semestre de 2016

Questão 01

Considere a classe Player apresentada a seguir, responsável pela representação de um jogador em um jogo de computador.

public class Player
{
  private String name;

  private Integer phase;

  private Double energy;

  public String getName() { return name; }

  public void setName(String name) { this.name = name; }

  public Integer getPhase() { return phase; }

  public void setPhase(Integer phase) { this.phase = phase; }

  public Double getEnergy() { return energy; }

  public void setEnergy(Double energy) { this.energy = energy; }
}

Conforme observado, a classe não armazenada nenhum informação para que o jogo possa ser recuperado posteriormente, caso o jogador venha a perder ou desistir da partida, pois a classe armazena apenas os valores correntes do jogador. Qual padrão de projeto deveria ser utilizado na classe Player para que o usuário possa salvar e retornar ao jogo posteriormente.

  1. Command - encapsula uma solicitação como um objeto, desta forma permitindo que você parametrize clientes com diferentes solicitações, enfileire ou registre (log) solicitações e suporte operações que podem ser desfeitas.
  2. 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.
  3. Prototype - especifica os tipos de objetos a serem criados usando uma instância prototípica e criar novos objetos copiando este protótipo.
  4. State - permite que um objeto altere seu comportamento quando seu estado interno muda. O objeto parecerá ter mudado sua classe.
  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.

Questão 02

Altere a classe Player para que a mesma possa salvar e retornar ao jogo posteriormente. Siga as recomendações estabelecidas pelo padrão de projeto selecionado na questão 01.

public class Player
{
  private String name;

  private Integer phase;

  private Double energy;

  public String getName() { return name; }

  public void setName(String name) { this.name = name; }

  public Integer getPhase() { return phase; }

  public void setPhase(Integer phase) { this.phase = phase; }

  public Double getEnergy() { return energy; }

  public void setEnergy(Double energy) { this.energy = energy; }

  public Object createMemento()
  {
    Memento memento = new Memento();

    memento.name = name;
    memento.phase = phase;
    memento.energy = energy;

    return memento;
  }

  public void setMemento(Object object)
  {
    if(object instanceof Memento)
    {
      Memento memento = (Memento) object;

      name = memento.name;
      phase = memento.phase;
      energy = memento.energy;
    }
  }

  private class Memento {

    private String name;

    private Integer phase;

    private Double energy;
  }
}

Questão 03

Na criação de fluxos de leitura e escrita na linguagem de programação Java, é possível combinar diversas funcionalidades em um único fluxo de dados, sem a necessidade de subclasses para todas as combinações possíveis, como pode ser observado no diagrama UML (Unified Modeling Language) apresentado a seguir, que apresenta parte da hierarquia de classes do fluxo de leitura.

Diagrama de classes da classe InputStream
Diagrama de classes da classe InputStream

Qual padrão de projeto foi adotado pela linguagem de programação Java para promover essa característica.

  1. Bridge - separa uma abstração da sua implementação, de modo que as duas possam variar independentemente.
  2. Composite - compõe 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.
  3. Decorator - atribui responsabilidades adicionais a um objeto dinamicamente. Os decorators fornecem uma alternativa flexível a subclasses para extensão da funcionalidade.
  4. 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 utilizam.
  5. 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 redefinam certos passos de um algoritmo sem mudar sua estrutura.

Questão 04

O padrão de projeto Singleton é um padrão de projeto de criação, cujo objetivo é garantir que a classe ofereça apenas uma única instância do objeto, que será controlada por ela mesma. Considere as seguintes implementações em Java do padrão de projeto Singleton.

  1. public class Singleton {
      private final static Singleton singleton = new Singleton();
      private Singleton() { }
      public static Singleton getInstance() { return singleton; }
    }
  2. public class Singleton {
      private static Singleton singleton;
      private Singleton() { }
      public static Singleton getInstance() {
        if(singleton == null) { singleton = new Singleton(); }
        return singleton;
      }
    }
  3. public class Singleton {
      private static Singleton singleton;
      private Singleton() { }
      public static synchronized Singleton getInstance() {
        if(singleton == null) { singleton = new Singleton(); }
        return singleton;
      }
    }
  4. public class Singleton {
      private static Singleton singleton;
      private Singleton() { }
      public static Singleton getInstance() {
        if(singleton == null) {
          synchronized(Singleton.class) { singleton = new Singleton(); }
        }
        return singleton;
      }
    }
  5. public class Singleton {
      private static Singleton singleton;
      private Singleton() { }
      public static Singleton getInstance() {
        if(singleton == null) {
          synchronized(Singleton.class) {
            if(singleton == null) { singleton = new Singleton(); }
          }
        }
        return singleton;
      }
    }

Todas as implementações apresentadas funcionam perfeitamente na existência de um único processo em execução, mas no caso da aplicação possuir vários processos (threads), apenas duas implementações garantem a existência de uma única instancia da classe, ou seja, são thread-safe. Quais são as duas implementações, que no caso da existência de threads, garantem a existência de uma única instancia da classe Singleton?

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

Questão 05

Na linguagem de programação Java, objetos do tipo String são considerados objetos imutáveis, ou seja, caso alguma alteração seja realizada em seus valores, novos objetos são criados. Em contrapartida, caso você tenha criado dois objetos com o mesmo valor, a linguagem armazena uma única instância na memória, evitando que você tenha objetos duplicados. Qual padrão de projeto foi adotado pela linguagem de programação Java para promover essa característica.

  1. Abstract Factory - fornece uma interface para criação de famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.
  2. 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.
  3. Flyweight - usa compartilhamento para suportar grandes quantidades de objetos, de granularidade fina, de maneira eficiente.
  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. 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 utilizam.

Questão 06

No desenvolvimento de sistemas computacionais, algumas vezes nos deparamos com problemas onde parte de um determinado algoritmo depende da implementação de classes filhas, mas a estrutura do algoritmo é única. Por exemplo, podemos ter uma classe que monta relatórios denominada Report. O algoritmo para montar relatórios é sempre o mesmo, consistindo nas seguintes operações:

  1. montar o cabeçalho
  2. montar o corpo
  3. montar o rodapé

Apesar da sequência de operações ser a mesma, os detalhes da implementação podem variar. Relatórios para a mesma empresa podem manter o cabeçalho e o rodapé e variar o conteúdo do corpo. Em outros cenários pode ser necessário variar também o cabeçalho e o rodapé. Qual padrão de projeto deveria ser utilizado para modelar as classes para atender aos diversos cenários?

  1. Builder - separa a construção de um objeto complexo da sua representação, de modo que o mesmo processo de construção possa criar diferentes representações.
  2. Façade fornece uma interface unificada para um conjunto de interfaces em um subsistema. O Façade define uma interface de nível mais alto que torna o subsistema mais fácil de usar.
  3. Interpreter - dada uma linguagem, define uma representação para sua gramática juntamente com um interpretador que usa a representação para interpretar sentenças nesta linguagem.
  4. Mediator - define um objeto que encapsula como um conjunto de objetos interage. O Mediator promove o acoplamento fraco ao evitar que os objetos se refiram explicitamente uns aos outros, permitindo que você varie suas interações independentemente.
  5. 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 redefinam certos passos de um algoritmo sem mudar sua estrutura.

Questão 07

Imagine o cenário onde você tem uma definição por interface Java do padrão de classes da entidade Temperature. Duas implementações foram criadas com tal interface e existe uma classe de gerenciamento UITemperature, que tem a responsabilidade de transmitir os dados das temperaturas para os elementos de uma interface gráfica, conforme apresentado no diagrama UML (Unified Modeling Language) a seguir.

Diagrama de classes da entidade Temperature
Diagrama de classes da entidade Temperature

Neste modelo temos três classes principais: Temperature (modelo do domínio de negócio), UITemperature (controle) e Panel (visualização). A classe UITemperature teria a seguinte codificação:

public class UITemperature {
  public void showTemperature(Panel panel, Temperature temperature) {
    panel.setTemperature(temperature.getDegree());
  }
}

Agora imagine que surgiu um novo sistema Java que deverá ser integrado ao sistema atual sem alterar o original. Neste sistema existe a seguinte implementação de TemperatureK.

Diagrama de classes da classe TemperatureK
Diagrama de classes da classe TemperatureK

Percebemos que apesar da temperatura apresentar as mesmas características e comportamentos, todos os nomes de métodos estão diferentes. Podemos imaginar que nesta situação a solução seria alterar a classe UITemperature, adicionando um novo método showTemperatureK.

public class UITemperature {
  public void showTemperature(Panel panel, Temperature temperature) {
    panel.setTemperature(temperature.getDegree());
  }

  public void showTemperatureK(Panel panel, TemperatureK temperature) {
    panel.setTemperature(temperature.getMeasure());
  }
}

A consequência é que a camada de controle tende a crescer a medida que novas inclusões são feitas no sistema causando uma dispersão das lógicas associadas as classes de representação da entidade Temperature. Todo o sistema terá que tratar de uma forma a temperatura padrão e de outra forma a temperatura em Kelvin e eventuais novas que surgirem. Este crescimento é bastante desordenado, uma vez que classes como Temperature, se comunicam com diversas partes do modelo. Qual padrão de projeto deveria ser utilizado para solucionar este problema com a inserção de novas temperaturas?

  1. Adapter - converte a interface de uma classe em outra interface, esperada pelos clientes. O Adapter permite que certas classes trabalhem em conjunto, pois de outra forma seria impossível por causa de suas interfaces incompatíveis.
  2. Factory Method - define uma interface para criar um objeto, mas deixa as subclasses decidirem qual classe a ser instanciada. O Factory Method permite a uma classe postergar (defer) a instanciação às subclasses.
  3. Iterator - fornece uma maneira de acessar sequencialmente os elementos de um objeto agregado sem expor sua representação subjacente.
  4. Proxy - fornece um objeto representante (surrogate), ou um marcador de outro objeto, para controlar o acesso ao mesmo.
  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.

Questão extra

Apresente o diagrama UML (Unified Modeling Language) da solução, adotando o padrão de projeto selecionado na questão 07.

Diagrama de classes da entidade Temperature
Diagrama de classes da entidade Temperature