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

From Wiki**3

(New page: {{TOCright}}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 objecto...)
 
(A classe de base)
Line 40: Line 40:
 
A classe de base de todas as entidades a criar é <tt>Obra</tt>. Esta classe, por um lado, impõe às suas subclasses a definição do método <tt>processa</tt> 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 (<tt>cria</tt>).
 
A classe de base de todas as entidades a criar é <tt>Obra</tt>. Esta classe, por um lado, impõe às suas subclasses a definição do método <tt>processa</tt> 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 (<tt>cria</tt>).
  
  <b>import</b><span style="color: #808000;"> java.util.ArrayList;</span>
+
<java5>
  <b>import</b><span style="color: #808000;"> java.lang.reflect.Constructor;</span>
+
import java.util.ArrayList;
  <b>import</b><span style="color: #808000;"> java.lang.reflect.InvocationTargetException;</span>
+
import java.lang.reflect.Constructor;
   
+
import java.lang.reflect.InvocationTargetException;
  <b>public abstract class</b> Obra {
+
 
    <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 Obra"</span>); }
+
  public abstract class Obra {
+
  static { System.out.println("Carregamento da classe Obra"); }
    <b>public abstract</b> <span style="color: #800000;">void</span> <span style="color: #000080;">processa</span>();
+
 
+
  public abstract void processa();
    <span style="color: #800000;">static</span> Obra <span style="color: #000080;">cria</span>(<span style="font-weight: bold;color: #0095ff;">String</span> dsc) {
+
 
      <span style="font-weight: bold;color: #0095ff;">String</span> dados[] = dsc.<span style="color: #000080;">split</span>(<span style="color: #dd0000;">":"</span>);
+
  static Obra cria(String dsc) {
      <b>try</b> {
+
    String dados[] = dsc.split(":");
        <span style="font-weight: bold;color: #0095ff;">ArrayList</span>&lt;<span style="font-weight: bold;color: #0095ff;">String</span>&gt; ctorargs = <b>new</b> <span style="font-weight: bold;color: #0095ff;">ArrayList</span>&lt;<span style="font-weight: bold;color: #0095ff;">String</span>&gt;(dados.<span style="color: #000080;">length</span>-<span style="color: #0000ff;">1</span>);
+
    try {
        <span style="font-weight: bold;color: #0095ff;">Class</span> tipo = <span style="font-weight: bold;color: #0095ff;">Class</span>.<span style="color: #000080;">forName</span>(dados[<span style="color: #0000ff;">0</span>]);
+
      ArrayList<String> ctorargs = new ArrayList<String>(dados.length-1);
        <b>for</b> (<span style="color: #800000;">int</span> ix = <span style="color: #0000ff;">1</span>; ix &lt; dados.<span style="color: #000080;">length</span>; ix++)
+
      Class tipo = Class.forName(dados[0]);
          ctorargs.<span style="color: #000080;">add</span>(ix-<span style="color: #0000ff;">1</span>, dados[ix]);
+
      for (int ix = 1; ix < dados.length; ix++)
        <span style="font-weight: bold;color: #0095ff;">Constructor</span> ctor = tipo.<span style="color: #000080;">getConstructors</span>()[<span style="color: #0000ff;">0</span>];  <span style="font-style: italic;color: #808080;">// hack? só existe um...</span>
+
        ctorargs.add(ix-1, dados[ix]);
        <b>return</b> (Obra)ctor.<span style="color: #000080;">newInstance</span>(ctorargs.<span style="color: #000080;">toArray</span>());
+
      Constructor ctor = tipo.getConstructors()[0];  // hack? só existe um...
      }
+
      return (Obra)ctor.newInstance(ctorargs.toArray());
      <b>catch</b> (<span style="font-weight: bold;color: #0095ff;">ClassNotFoundException</span> e) {  <span style="font-style: italic;color: #808080;">// forName</span>
+
    }
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"!! TIPO DE OBRA DESCONHECIDO !!"</span>);
+
    catch (ClassNotFoundException e) {  // forName
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
+
      System.err.println("!! TIPO DE OBRA DESCONHECIDO !!");
        <b>return null</b>;
+
      System.err.println(e);
      }
+
      return null;
      <b>catch</b> (<span style="font-weight: bold;color: #0095ff;">InstantiationException</span> e) {  <span style="font-style: italic;color: #808080;">// newInstance</span>
+
    }
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"!! TIPO DE OBRA ABSTRACTO !!"</span>);
+
    catch (InstantiationException e) {  // newInstance
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
+
      System.err.println("!! TIPO DE OBRA ABSTRACTO !!");
        <b>return null</b>;
+
      System.err.println(e);
      }
+
      return null;
      <b>catch</b> (<span style="font-weight: bold;color: #0095ff;">IllegalAccessException</span> e) {  <span style="font-style: italic;color: #808080;">// newInstance</span>
+
    }
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"!! TIPO DE OBRA SEM CONSTRUCTOR ACESSÃ?VEL!!"</span>);
+
    catch (IllegalAccessException e) {  // newInstance
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
+
      System.err.println("!! TIPO DE OBRA SEM CONSTRUCTOR ACESSÍVEL!!");
        <b>return null</b>;
+
      System.err.println(e);
      }
+
      return null;
      <b>catch</b> (<span style="font-weight: bold;color: #0095ff;">IllegalArgumentException</span> e) {  <span style="font-style: italic;color: #808080;">// newInstance</span>
+
    }
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"!! TIPO DE OBRA MAL DESCRITO !!"</span>);
+
    catch (IllegalArgumentException e) {  // newInstance
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
+
      System.err.println("!! TIPO DE OBRA MAL DESCRITO !!");
        <b>return null</b>;
+
      System.err.println(e);
      }
+
      return null;
      <b>catch</b> (<span style="font-weight: bold;color: #0095ff;">InvocationTargetException</span> e) {  <span style="font-style: italic;color: #808080;">// newInstance</span>
+
    }
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(<span style="color: #dd0000;">"!! TIPO DE OBRA COM CONSTRUCTOR EM APUROS !!"</span>);
+
    catch (InvocationTargetException e) {  // newInstance
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
+
      System.err.println("!! TIPO DE OBRA COM CONSTRUCTOR EM APUROS !!");
        <b>return null</b>;
+
      System.err.println(e);
      }
+
      return null;
    }
+
    }
   
+
  }
  }
+
 
 +
  }
 +
</java5>
  
 
Note-se o tratamento de várias excepções, em particular, o tratamento da excepção <tt>ClassNotFoundException</tt>, que tem, neste contexto especial, um significado para a aplicação algo distinto do habitual.
 
Note-se o tratamento de várias excepções, em particular, o tratamento da excepção <tt>ClassNotFoundException</tt>, que tem, neste contexto especial, um significado para a aplicação algo distinto do habitual.

Revision as of 12:53, 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:

 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(); }
 }

Para livros:

 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(); }
 }

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