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

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...)
 
 
(29 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{TOCright}}O padrão "simple" factory fornece uma forma de criar objectos a partir de uma descrição externa.
#REDIRECT [[ist:"Simple" Factory (padrão de desenho)]]
 
== 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 (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.
 
  <span style="font-weight: bold;">interface</span> Folheável {
    <span style="color: #800000;">void</span> <span style="color: #000080;">folhear</span>();
  }
 
  <span style="font-weight: bold;">interface</span> Legível {
    <span style="color: #800000;">void</span> <span style="color: #000080;">ler</span>();
  }
 
  <span style="font-weight: bold;">interface</span> Rodopiável {
    <span style="color: #800000;">void</span> <span style="color: #000080;">rodopiar</span>();
  }
 
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>).
 
  <b>import</b><span style="color: #808000;"> java.util.ArrayList;</span>
  <b>import</b><span style="color: #808000;"> java.lang.reflect.Constructor;</span>
  <b>import</b><span style="color: #808000;"> java.lang.reflect.InvocationTargetException;</span>
  <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>); }
    <b>public abstract</b> <span style="color: #800000;">void</span> <span style="color: #000080;">processa</span>();
    <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>);
      <b>try</b> {
        <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>);
        <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>]);
        <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++)
          ctorargs.<span style="color: #000080;">add</span>(ix-<span style="color: #0000ff;">1</span>, dados[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>
        <b>return</b> (Obra)ctor.<span style="color: #000080;">newInstance</span>(ctorargs.<span style="color: #000080;">toArray</span>());
      }
      <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>);
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
        <b>return null</b>;
      }
      <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>);
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
        <b>return null</b>;
      }
      <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>);
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
        <b>return null</b>;
      }
      <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>);
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
        <b>return null</b>;
      }
      <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>);
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">err</span>.<span style="color: #000080;">println</span>(e);
        <b>return null</b>;
      }
    }
  }
 
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:
 
  <b>public class</b> DVD <b>extends</b> Obra <b>implements</b> Rodopiável, Legível {
    <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>); }
    <span style="font-weight: bold;color: #0095ff;">String</span> _título;
    <span style="font-weight: bold;color: #0095ff;">String</span> _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;
    }
    <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>); }
    <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>); }
    <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:
 
  <b>public class</b> Livro <b>extends</b> Obra <b>implements</b> Folheável, Legível {
    <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>); }
    <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 ===
 
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).
 
  <b>import</b><span style="color: #808000;"> java.util.ArrayList;</span>
  <b>import</b><span style="color: #808000;"> java.io.BufferedReader;</span>
  <b>import</b><span style="color: #808000;"> java.io.FileReader;</span>
  <b>import</b><span style="color: #808000;"> java.io.IOException;</span>
 
  <b>public class</b> Teste {
    <b>public</b> <span style="color: #800000;">static</span> <span style="color: #800000;">void</span> <span style="color: #000080;">main</span>(<span style="font-weight: bold;color: #0095ff;">String</span>[] args) <b>throws</b> <span style="font-weight: bold;color: #0095ff;">IOException</span> {
      <span style="font-weight: bold;color: #0095ff;">String</span> entrada = <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">getProperty</span>(<span style="color: #dd0000;">"obras"</span>, <span style="color: #dd0000;">"obras.txt"</span>);
      <span style="font-weight: bold;color: #0095ff;">BufferedReader</span> r = <b>new</b> <span style="font-weight: bold;color: #0095ff;">BufferedReader</span>(<b>new</b> <span style="font-weight: bold;color: #0095ff;">FileReader</span>(entrada));
      <span style="font-weight: bold;color: #0095ff;">String</span> linha;
      <span style="font-weight: bold;color: #0095ff;">ArrayList</span>&lt;Obra&gt; obras = <b>new</b> <span style="font-weight: bold;color: #0095ff;">ArrayList</span>&lt;Obra&gt;();
      <b>while</b> ((linha = r.<span style="color: #000080;">readLine</span>()) != <b>null</b>) {
        Obra o = Obra.<span style="color: #000080;">cria</span>(linha);
        obras.<span style="color: #000080;">add</span>(o);
        <span style="font-weight: bold;color: #0095ff;">System</span>.<span style="color: #000080;">out</span>.<span style="color: #000080;">println</span>(o);
      }
      r.<span style="color: #000080;">close</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;">"****************"</span>);
      <b>for</b> (Obra o: obras) o.<span style="color: #000080;">processa</span>();
    }
  }
 
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:OOP]]

Latest revision as of 14:09, 7 November 2018