Difference between revisions of ""Simple" Factory (padrão de desenho)"

From Wiki**3

(A classe de base)
(As classes das obras)
Line 97: Line 97:
  
 
Para DVDs:
 
Para DVDs:
 +
<java5>
 +
public class DVD extends Obra implements Rodopiável, Legível {
 +
  static { System.out.println("Carregamento da classe DVD"); }
  
  <b>public class</b> DVD <b>extends</b> Obra <b>implements</b> Rodopiável, Legível {
+
  String _título;
    <span style="color: #800000;">static</span> { <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">out</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"Carregamento da classe DVD"</span>); }
+
  String _realizador;
+
 
    <span style="font-weight: bold;color: #0095ff;">String</span> _título;
+
  public DVD(String título, String realizador) {
    <span style="font-weight: bold;color: #0095ff;">String</span> _realizador;
+
    _título    = título;
+
    _realizador = realizador;
    <b>public</b> <span style="color: #000080;">DVD</span>(<span style="font-weight: bold;color: #0095ff;">String</span> título, <span style="font-weight: bold;color: #0095ff;">String</span> realizador) {
+
  }
      _título    = título;
+
 
      _realizador = realizador;
+
  public String toString() { return "DVD:" + _título + ":" + _realizador; }
    }
+
  public void ler()      { System.out.println("LER "      + this); }
+
  public void rodopiar() { System.out.println("RODOPIAR " + this); }
    <b>public</b> <span style="font-weight: bold;color: #0095ff;">String</span> <span style="color: #000080;">toString</span>() { <b>return</b> <span style="color: #dd0000;">"DVD:"</span> + _título + <span style="color: #dd0000;">":"</span> + _realizador; }
+
 
    <b>public</b> <span style="color: #800000;">void</span> <span style="color: #000080;">ler</span>()      { <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">out</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"LER "</span>     + <b>this</b>); }
+
  public void processa() { rodopiar(); ler(); }
    <b>public</b> <span style="color: #800000;">void</span> <span style="color: #000080;">rodopiar</span>() { <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">out</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"RODOPIAR "</span> + <b>this</b>); }
+
}
+
</java5>
    <b>public</b> <span style="color: #800000;">void</span> <span style="color: #000080;">processa</span>() { <span style="color: #000080;">rodopiar</span>(); <span style="color: #000080;">ler</span>(); }
 
  }
 
  
 
Para livros:
 
Para livros:
 +
<java5>
 +
public class Livro extends Obra implements Folheável, Legível {
 +
  static { System.out.println("Carregamento da classe Livro"); }
 +
 +
  String _título;
 +
  String _autor;
 +
  String _isbn;
 +
 +
  public Livro(String título, String autor, String isbn) {
 +
    _título = título;
 +
    _autor  = autor;
 +
    _isbn  = isbn;
 +
  }
 +
 +
  public String toString() { return "Livro:" + _título + ":" + _autor + ":" + _isbn; }
 +
  public void ler()    { System.out.println("LER "    + this); }
 +
  public void folhear() { System.out.println("FOLHEAR " + this); }
  
  <b>public class</b> Livro <b>extends</b> Obra <b>implements</b> Folheável, Legível {
+
  public void processa() { folhear(); ler(); }
    <span style="color: #800000;">static</span> { <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">out</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"Carregamento da classe Livro"</span>); }
+
  }
+
</java5>
    <span style="font-weight: bold;color: #0095ff;">String</span> _título;
 
    <span style="font-weight: bold;color: #0095ff;">String</span> _autor;
 
    <span style="font-weight: bold;color: #0095ff;">String</span> _isbn;
 
 
    <b>public</b> <span style="color: #000080;">Livro</span>(<span style="font-weight: bold;color: #0095ff;">String</span> título, <span style="font-weight: bold;color: #0095ff;">String</span> autor, <span style="font-weight: bold;color: #0095ff;">String</span> isbn) {
 
      _título = título;
 
      _autor  = autor;
 
      _isbn  = isbn;
 
    }
 
 
    <b>public</b> <span style="font-weight: bold;color: #0095ff;">String</span> <span style="color: #000080;">toString</span>() { <b>return</b> <span style="color: #dd0000;">"Livro:"</span> + _título + <span style="color: #dd0000;">":"</span> + _autor + <span style="color: #dd0000;">":"</span> + _isbn; }
 
    <b>public</b> <span style="color: #800000;">void</span> <span style="color: #000080;">ler</span>()     { <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">out</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"LER "</span>    + <b>this</b>); }
 
    <b>public</b> <span style="color: #800000;">void</span> <span style="color: #000080;">folhear</span>() { <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">out</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"FOLHEAR "</span> + <b>this</b>); }
 
   
 
    <b>public</b> <span style="color: #800000;">void</span> <span style="color: #000080;">processa</span>() { <span style="color: #000080;">folhear</span>(); <span style="color: #000080;">ler</span>(); }
 
  }
 
  
 
=== Aplicação exemplo ===
 
=== Aplicação exemplo ===

Revision as of 12:55, 1 October 2010

O padrão "simple" factory fornece uma forma de criar objectos a partir de uma descrição externa.

Exemplo

Neste exemplo, apresenta-se a criação dinâmica de objectos de um determinado tipo, a partir de uma descrição textual desses objectos.

Este exemplo utiliza informação de tipos em tempo de execução, mas qualquer outro que realizasse a mesma função por outras vias seria admissível.

Introdução

Considere-se o ficheiro obras.txt, contendo descrições de DVDs (título e realizador) e de Livros (título, autor e ISBN):

 DVD:Era uma vez na amadora:Fernando Fonseca
 DVD:Lumiar selvagem:Pedro Fonseca
 Livro:A arte de sobreviver no 36:Joao Fonseca:1234567890
 Livro:Bairro alto e o budismo zen:Zun Tse Fonseca:1234567891
 DVD:48 horas para o exame:Orlando Fonseca
 Livro:Lux e o insucesso escolar - Uma visao matematica:Carlos Alberto Fonseca:1234567892

A ideia da aplicação que se descreve de seguida é a leitura de cada linha como se da criação de um objecto se tratasse. Assim, o primeiro campo (os campos são separados por ":") define a classe do objecto e os restantes campos são passados como argumentos ao constructor da classe. Pretende-se ainda que a implementação seja suficientemente flexível para que resista à utilização de descrições erradas ou de descrições de objectos desconhecidos.

Interfaces

Além dos aspectos acima, cada obra é classificada com uma ou mais interfaces, sendo o seu comportamento definido por elas.

 interface Folheável {
   void folhear();
 }
 interface Legível {
   void ler();
 }
 interface Rodopiável {
   void rodopiar();
 }

Estas interfaces não são realmente utilizadas para os aspectos de criação dos objectos, mas permitem ilustrar a utilização de código específico em conjunto com código genérico.

A classe de base

A classe de base de todas as entidades a criar é Obra. Esta classe, por um lado, impõe às suas subclasses a definição do método processa e, por outro, recorrendo a uma fábrica simples que, fazendo uso de informação de tipos em tempo de execução, permite criar instâncias das suas subclasses, de acordo com uma descrição passada como argumento (cria).

<java5>

import java.util.ArrayList;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public abstract class Obra {
  static { System.out.println("Carregamento da classe Obra"); }
  public abstract void processa();
  static Obra cria(String dsc) {
    String dados[] = dsc.split(":");
    try {
      ArrayList<String> ctorargs = new ArrayList<String>(dados.length-1);
      Class tipo = Class.forName(dados[0]);
      for (int ix = 1; ix < dados.length; ix++)
        ctorargs.add(ix-1, dados[ix]);
      Constructor ctor = tipo.getConstructors()[0];  // hack? só existe um...
      return (Obra)ctor.newInstance(ctorargs.toArray());
    }
    catch (ClassNotFoundException e) {  // forName
      System.err.println("!! TIPO DE OBRA DESCONHECIDO !!");
      System.err.println(e);
      return null;
    }
    catch (InstantiationException e) {  // newInstance
      System.err.println("!! TIPO DE OBRA ABSTRACTO !!");
      System.err.println(e);
      return null;
    }
    catch (IllegalAccessException e) {  // newInstance
      System.err.println("!! TIPO DE OBRA SEM CONSTRUCTOR ACESSÍVEL!!");
      System.err.println(e);
      return null;
    }
    catch (IllegalArgumentException e) {  // newInstance
      System.err.println("!! TIPO DE OBRA MAL DESCRITO !!");
      System.err.println(e);
      return null;
    }
    catch (InvocationTargetException e) {  // newInstance
      System.err.println("!! TIPO DE OBRA COM CONSTRUCTOR EM APUROS !!");
      System.err.println(e);
      return null;
    }
  }
}

</java5>

Note-se o tratamento de várias excepções, em particular, o tratamento da excepção ClassNotFoundException, que tem, neste contexto especial, um significado para a aplicação algo distinto do habitual.

Note-se ainda o tratamento de InvocationTargetException, que permite lidar com as excepções específicas do constructor da obra em causa (exception chaining).

As classes das obras

Para DVDs: <java5>

public class DVD extends Obra implements Rodopiável, Legível {
  static { System.out.println("Carregamento da classe DVD"); }
  String _título;
  String _realizador;
  public DVD(String título, String realizador) {
    _título     = título;
    _realizador = realizador;
  }
  public String toString() { return "DVD:" + _título + ":" + _realizador; }
  public void ler()      { System.out.println("LER "      + this); }
  public void rodopiar() { System.out.println("RODOPIAR " + this); }
  public void processa() { rodopiar(); ler(); }
}

</java5>

Para livros: <java5>

public class Livro extends Obra implements Folheável, Legível {
  static { System.out.println("Carregamento da classe Livro"); }
  String _título;
  String _autor;
  String _isbn;
  public Livro(String título, String autor, String isbn) {
    _título = título;
    _autor  = autor;
    _isbn   = isbn;
  }
  public String toString() { return "Livro:" + _título + ":" + _autor + ":" + _isbn; }
  public void ler()     { System.out.println("LER "     + this); }
  public void folhear() { System.out.println("FOLHEAR " + this); }
  public void processa() { folhear(); ler(); }
}

</java5>

Aplicação exemplo

Esta aplicação lÃ?ª o ficheiro de obras (propriedade obras) e processa cada linha, criando os objectos correspondentes. Depois de lidas, as obras são processadas (uniformemente).

 import java.util.ArrayList;
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
 
 public class Teste {
   public static void main(String[] args) throws IOException {
     String entrada = System.getProperty("obras", "obras.txt");
     BufferedReader r = new BufferedReader(new FileReader(entrada));
     String linha;
     ArrayList<Obra> obras = new ArrayList<Obra>();
     while ((linha = r.readLine()) != null) {
       Obra o = Obra.cria(linha);
       obras.add(o);
       System.out.println(o);
     }
     r.close();
     System.out.println("****************");
     for (Obra o: obras) o.processa();
   }
 }

A saída da aplicação de teste é a que se apresenta. Note-se a ordem de carregamento das classes.

 % java -Dobras=obras.txt Teste
 Carregamento da classe Obra
 Carregamento da classe DVD
 DVD:Era uma vez na amadora:Fernando Fonseca
 DVD:Lumiar selvagem:Pedro Fonseca
 Carregamento da classe Livro
 Livro:A arte de sobreviver no 36:Joao Fonseca:1234567890
 Livro:Bairro alto e o budismo zen:Zun Tse Fonseca:1234567891
 DVD:48 horas para o exame:Orlando Fonseca
 Livro:Lux e o insucesso escolar - Uma visao matematica:Carlos Alberto Fonseca:1234567892
 ****************
 RODOPIAR DVD:Era uma vez na amadora:Fernando Fonseca
 LER DVD:Era uma vez na amadora:Fernando Fonseca
 RODOPIAR DVD:Lumiar selvagem:Pedro Fonseca
 LER DVD:Lumiar selvagem:Pedro Fonseca
 FOLHEAR Livro:A arte de sobreviver no 36:Joao Fonseca:1234567890
 LER Livro:A arte de sobreviver no 36:Joao Fonseca:1234567890
 FOLHEAR Livro:Bairro alto e o budismo zen:Zun Tse Fonseca:1234567891
 LER Livro:Bairro alto e o budismo zen:Zun Tse Fonseca:1234567891
 RODOPIAR DVD:48 horas para o exame:Orlando Fonseca
 LER DVD:48 horas para o exame:Orlando Fonseca
 FOLHEAR Livro:Lux e o insucesso escolar - Uma visao matematica:Carlos Alberto Fonseca:1234567892
 LER Livro:Lux e o insucesso escolar - Uma visao matematica:Carlos Alberto Fonseca:1234567892