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

From Wiki**3

(Exemplo)
Line 8: Line 8:
  
 
Este exemplo utiliza [[Informação de Tipos em Tempo de Execução (Java)|informação de tipos em tempo de execução]], mas qualquer outro que realizasse a mesma função por outras vias seria admissível.
 
Este exemplo utiliza [[Informação de Tipos em Tempo de Execução (Java)|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 <tt>obras.txt</tt>, contendo descrições de DVDs (título e realizador) e de Livros (título, autor e [[wikipedia:ISBN|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 "<tt>:</tt>") 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.
 
 
<java5>
 
interface Folheável {
 
  void folhear();
 
}
 
</java5>
 
 
<java5>
 
interface Legível {
 
  void ler();
 
}
 
</java5>
 
 
<java5>
 
interface Rodopiável {
 
  void rodopiar();
 
}
 
</java5>
 
 
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 é <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>).
 
 
<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 <tt>ClassNotFoundException</tt>, que tem, neste contexto especial, um significado para a aplicação algo distinto do habitual.
 
 
Note-se ainda o tratamento de <tt>InvocationTargetException</tt>, 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 <tt>obras</tt>) e processa cada linha, criando os objectos correspondentes. Depois de lidas, as obras são processadas (uniformemente).
 
<java5>
 
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();
 
  }
 
}
 
</java5>
 
 
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'''
 
  <font color="green">Carregamento da classe Obra</font>
 
  <font color="green">Carregamento da classe DVD</font>
 
  DVD:Era uma vez na amadora:Fernando Fonseca
 
  DVD:Lumiar selvagem:Pedro Fonseca
 
  <font color="green">Carregamento da classe Livro</font>
 
  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
 
  
 
[[category:Ensino]]
 
[[category:Ensino]]
 
[[category:PO]]
 
[[category:PO]]
 
[[category:PO Exemplos|S]]
 
[[category:PO Exemplos|S]]

Revision as of 12:25, 14 November 2013

[Expand] Programação com Objectos
Introduction
Creation and Destruction
Inheritance & Composition
Abstraction & Polymorphism
Code Organization
Java Topics
Inner Classes
Enumerations
Data Structures
Exceptions
Input/Output
RTTI
Other Topics
JUnit Tests
UML Topics
Design Patterns
"Simple" Factory
Composite & Visitor
Command
Strategy & State
Template Method
Observer
Abstract Factory
Decorator & Adapter
Façade (aka Facade)

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.