Design Patterns no Java SE: o Template Method

Por Paulo Silveira em 04/09/07

Quando alguém aprende o que é Design Pattern, ou mesmo um novo Design Pattern, fica com aquele sentimento de que já viu isso em algum lugar antes. A API do Java SE é um excelente lugar para encontrar milhares de exemplos de Design Patterns. Só a java.util, a java.io e a java.lang já são suficientes para estudar os mais usados.

A classe abstrata java.io.InputStream é um excelente exemplo. Ela possui um conjunto de métodos para leitura de bytes, porém apenas um deles é abstrato: o método read que lê apenas um único byte. Segue seu fonte:

public abstract int read() throws IOException;

Ele é abstrato pois essa classe não sabe exatamente de onde será realizada a leitura: da entrada padrão? de um arquivo? de uma socket? Esse comportamento vai ser definido através da reescrita desse método em uma de suas subclasses concretas: FileInputStream, SocketInputStream, ByteArrayInputStream, entre outras. Essas sim sabem realizar a operação de leitura de um byte.

Se a classe InputStream não sabe ler um byte, como então é possível existir um método read que recebe um array de bytes a ser preenchido pela leitura, que não seja abstrato? Vamos ver o fonte deste método:

public int read(byte b[]) throws IOException {
   return read(b, 0, b.length);
}

Este por sua vez esta invocando o método sobrecarregado do read que recebe, além da array a ser preenchida, a posição inicial e quantos bytes devem ser lidos. O fonte deste método está abaixo:

01    public int read(byte b[]int off, int lenthrows IOException {
02       if (b == null) {
03          throw new NullPointerException();
04       else if (off < || len < || len > b.length - off) {
05          throw new IndexOutOfBoundsException();
06       else if (len == 0) {
07          return 0;
08       }
09 
10       int c = read();
11       if (c == -1) {
12          return -1;
13       }
14    
15       b[off(bytec;
16 
17       int i = 1;
18       try {
19          for (; i < len ; i++) {
20             c = read();
21             if (c == -1) {
22                break;
23             }
24             b[off + i(byte)c;
25          }
26       catch (IOException ee) {
27       }
28       return i;
29    }

Nas linhas 10 e 20 temos invocações ao método read que é abstrato! Isso é possível pois sabemos que não existe como instanciar a classe InputStream: ela é abstrata. Essa invocação recairá sobre um objeto que foi instanciado, logo ele possuirá uma implementação deste método read.

Esse é uma ótima ilustração do Template Method. Os métodos read que lêem mais de um byte são templates: eles possuem o algoritmo em si, mas ainda falta um pouco para que toda a funcionalidade deles esteja pronta. Essa parte que falta é suprida com a implementação concreta do método read nas classes filhas de InputStream. Quando a classe filha implementa esse método, os demais métodos de InputStream que dependem deste (os template methods) estarão prontos para uso!

Obviamente a OutputStream funciona de maneira análoga. No java.io ainda encontramos o Decorator Pattern, na java.awt o Composite Pattern, no java.lang temos o Builder e no java.util temos Iterator, Strategy, Prototype e muitos outros. Qual é seu exemplo preferido de Design Pattern dentro do Java SE?

3 Comments »

  1. Recentemente precisei implementar um Observer em Java. Antes de implementar na mão resolvi pesquisar e descobri que no pacote java.util já tem a interface Observable e a classe abstrata Observer!

    Mão na roda!

    Comment by Nico — September 5, 2007 @ 4:08 am

  2. Olá,

    Muita boa essa colocação. É importante mostrar na prática a utilização de Design Patterns e nada melhor que a própria API para servir de exemplo :-)

    Um abraço!

    Comment by Glaucio Guerra — September 6, 2007 @ 11:05 am

  3. Nessa thread do GUJ tem mais exemplos praticos da api do java
    http://guj.com.br/posts/list/98386.java

    Comment by Paulo Silveira — July 30, 2008 @ 3:35 am

RSS feed for comments on this post. TrackBack URL

Leave a comment