Actividade


  1. Aplicação de padrões de desenho: Facade, State, Abstract Factory, Adapter, Observer, Decorator
  2. Resolução do exercício EP9 para avaliação

Enunciado da Aula

1º Exercício

Suponha que lhe pediram para desenvolver uma biblioteca de formas geométricas. Como resultado produziu o seguinte código:


public interface Shape {
  void draw();
  void resize(int ratio) throws CanotResizeException;
  void setHidden(boolean hidden);
}

public class Rectangle implements Shape {
  private boolean _isHidden;

  @Override public void draw() {
    if (!_isHidden) System.out.println("Drawing Rectangle");
  }

  @Override public void resize(int ratio) {
    // code for revising this rectangle
  }

  @Override public void setHidden(boolean h) {
    _isHidden = h;
  }
  // more attributes and code
}

public class Circle implements Shape {
  // ...
}


e desenvolveu uma aplicação de desenho que lida com os diferentes tipos de Shape existentes. Esta aplicação segue o princípio aberto/fechado pelo que a definição de novos tipos de Shape não implica alterações no código da aplicação de desenho.

Entretanto, durante o desenvolvimento de novas formas geométricas, descobriu que havia outras formas que já tinham sido desenvolvidas no contexto de outro projecto mas que têm uma interface um pouco diferente. De seguida apresentamos um exemplo de uma das formas geométricas desenvolvidas no contexto do outro projecto.

public interface GeometricShape {
  double area();
  void drawShape();
}

public class Triangle implements GeometricShape {
  // sides
  private final double a;
  private final double b;
  private final double c;
  public Triangle() {
    this(1.0d, 1.0d, 1.0d);
  }

  public Triangle(double a, double b, double c) {
    this.a = a;
    this.b = b;
    this.c = c;
  }

  @Override public double area() {
    double s = (a + b + c) / 2;
    return Math.sqrt(s * (s - a) * (s - b) * (s - c));
  }
  
  @Override public void drawShape() {
    System.out.println("Drawing Triangle with area: " + area());
  }
}

Aplicando um ou mais padrões de desenho, construa uma solução que permite reutilizar o código destas formas geométricas desenvolvidas no contexto do outro projecto na aplicação de desenho. Idealmente não deve ser necessário alterar nem a aplicação de desenho nem o o código destas formas geométricas

Após ter construído a sua solução, considere que a interface Shape tem um método adicional (String  getDescription()) que deve devolver o nome da forma geométrica. A classe Rectangle deve agora concretizar este método retornando a cadeia de caracteres "Rectangle". Qual o impacto deste método extra na solução desenvolvida anteriormente?

2º Exercício

Considere a seguinte classe
public class ArCondicionado {

  private void aquece() { ... }
  private void arrefece() { ... }
  private void colocaVelocidade(int vel)  { ... }

  public void desliga() { ... }
  public void liga() { ... }

  public void alteraVelocidade() { ... }

  public void troca() { ... }

  public String obtemFuncionamento()  { ... }
}

que representa a interface de um aparelho de ar  condicionado. Este aparelho permite aquecer ou arrefecer e tem três velociades de ventilação (representados pelos números 1, 2 e 3). É possível ligar ou desligar o aparelho (via métodos liga() e desliga()). Quando se liga um aparelho, o aparelho aquece com velocidade 1. A velocidade do aparelho depende se está a aquecer ou a arrefecer. Em aquecimento, o aparelho só tem as velociades 1 e 2. Em modo arrefecimento só tem as velocidades 2 e 3. O método troca() permite trocar o modo de funcionamento de um ar condicionado ligado, passando a aquecer se estiver a arrefecer e vice-versa desde que as velocidades sejam compatíveis. Assim, só é possível trocar caso a velocidade seja 2. O método alteraVelocidade() altera a velocidade de um aparelho ligado. Por exemplo, em modo aquecimento, se a velociade for 1 passa para 2 e se for 2 passa para 1. Semelhante se estiver a arrefecer. Os métodos privados aquece(), arrefece() e colocaVelocidade() são utilizados internamente pela classe para colocar o aparelho a realizar o pretendido. Aplicando o padrão correcto, concretize agora os métodos públicos da classe por forma a que o código seja legível e seja relativamente fácil de alterar o modo de funcionamento do ar condicionado. O método obtemFuncionamento() devolve uma cadeia de caracteres que indica o modo em que o aparelho está, por exemplo, "Desligado" ou "Aquecer, velocidade 1". Colocar a velocidade a 0 desliga o aparelho de ar condicionado.

3º Exercício


Considere a seguinte classe TestSpan que representa um texto:

public class TextSpan implements TextItem {
 
  /** The text in this span. */
  private String _text;
 
  /**
   * @param text the text in this span.
   **/
   public TextSpan(String text) {
     _text = text;
   }
 
   /**
    * Renders the text of this TextSpan
    * @return the rendered text
    **/
    public String render() {
      return "<span>" + _text + "</span>";
    }
}


public interface TextItem {
	/**
	 * Text items can be rendered.
	 * 
	 * @return rendered text item.
	 */
	String render();
}

O método render() tem como funcionalidade devolver a cadeia de caracteres que representa o texto. 

O código actual desta classe não permite modificação do aspecto do texto, permitindo que este possa ser apresentado em negritoitálicosublinhado, ou em combinações variadas (e.g. negrito e itálico ou itálico sublinhado, etc.).

Pretende-se agora ter a possibilidade de poder modificar dinamicamente o aspecto de um texto sem que isso provoque alterações no código da aplicação já realizado. Represente as características gráficas da seguinte forma:

  • normal <span>normal</span>
  • negrito <b>negrito</b>
  • itálico <i>itálico</i>
  • sublinhado <u>sublinhado</u>

Qual o padrão de desenho a aplicar neste caso?

Exemplifique a aplicação do padrão escolhido para o caso do negrito e itálico.

4º Exercício


Considere o seguinte domínio.
Os clientes de uma empresa são identificados pelo nome (cadeia de caracteres) e possuem um número de telefone. Para cada cliente, a empresa mantém um registo das vendas realizadas.Cada vez que um cliente realiza uma dada compra o método realizaCompra(Venda d) de Cliente é invocado com a compra efectuada (a classe venda mantém o item comprado e o seu preço). Os clientes inicialmente não usufruem de descontos. No entanto, à medida que vão fazendo compras, o processo de fidelização da empresa vai introduzindo benefícios para clientes frequentes. Assim, para clientes que façam pelo menos cinco compras, o desconto passa para 5%; para clientes que façam pelo menos 100 compras, o desconto passa para 10%; se o cliente fizer mais do que 1000 compras, o desconto passa para 15%. Deve ser possível introduzir novas modalidades de recompensa, as quais podem depender de outros factores relacionados com o cliente (por exemplo o valor das compras efectuadas)  e novas funcionalidades dependentes do escalão do cliente (por exemplo aceder a promoções) com um custo reduzido no código já existente .Assim, deve ser fácil realizar as novas alterações no código já existente. Aplique um ou mais padrões de desenho por forma a concretizar este requisito.

5º Exercício


Considere o seguinte domínio. Uma loja tem produtos para vender e clientes. Um produto tem uma descrição e um preço. A loja permite colocar um produto em promoção através do método colocaEmPromocao definido em Loja. Este método recebe como argumentos o produto a colocar em promoção e o valor do desconto a a aplicar (um número inteiro entre 0 e 100). Considere agora que quer concretizar o seguinte requisito: Por forma a optimizar as suas vendas, é importante que cada loja seja capaz de avisar os clientes que tenham mostrado interesse nos produtos em promoção. Em qualquer instante, um cliente pode mostrar interesse em ser avisado sempre que a loja coloca um produto em promoção ou pode cancelar o seu interesse. Além dos clientes, a solução deverá permitir que outros tipos de entidades possam vir também a poder mostrar interesse em serem avisadas quando um produto fica em promoção. Aplicando um ou mais padrões de desenho concretize este novo requisito realizando novas classes e as modificações necessárias às entidades do domínio já existentes. Na solução encontrada, considere que sempre que um cliente recebe a notificação de um produto em promoção, deve ser escrito no terminal a descrição e preço do produto em promoção e o seu valor de desconto.