themeless

23/10/2009

Services, transações e proxies dinâmicos – parte I

Arquivado em: design patterns, java — tnaires @ 00:44

Introdução

No primeiro semestre deste ano cursei uma disciplina na faculdade onde o trabalho final consistia em escrever um software usando apenas Hibernate e JSF. Desenvolvi então um software de gestão de transporte de cargas, que poderia ser comercializado para empresas que fazem uso de uma frota de veículos para realizar transportes rodoviários.

Falando um pouco sobre sua arquitetura, ele dispõe de uma camada de aplicação composta de serviços que são requisitados pela camada de apresentação – nesse caso, pelos managed beans. O código cliente conhece apenas a interface desse serviço, expressa no código abaixo:

interface EntityService<T, ID extends Serializable> {
    void create(Map<String, Object> parameters);
    Collection<T> readAll();
    T read(ID id);
    Collection readByParameters(Map<String, Object> parameters);
    void update(Map<String, Object> parameters);
    void delete(T t);
}

Cada serviço da camada deve ser expresso através de uma interface que estenda EntityService. Por exemplo, o código abaixo corresponde ao serviço de cadastro de veículos.

public interface VeiculoService extends EntityService<Veiculo, String> {
    // Declaram-se aqui outras operações requeridas por esse serviço.
}

A implementação desse serviço deve conter o corpo para todos os métodos declarados nas duas interfaces. Note que a mesma não precisa ser pública.

class VeiculoServiceImpl implements VeiculoService {
    // Fornece implementações para todos os métodos.
}

Há desvantagens nessa abordagem. Nem sempre é conveniente disponibilizar todos os serviços declarados em EntityService para uma determinada entidade. Por exemplo, e se algum requisito do projeto exigisse que não fosse possível alterar veículos? O código abaixo ilustra uma solução possível.

class VeiculoServiceImpl implements VeiculoService {
    // Não é possível alterar veículos.
    public void update(Map<String, Object> parameters) {
        throw new UnsupportedOperationException("Operação não permitida.");
    }
}

Porém, a discussão do que seria melhor ou não não está no escopo desse artigo, embora fosse interessante continuá-la na seção de comentários.

Finalmente, a classe abaixo é usada pela camada de apresentação para requisitar os serviços.

public class ApplicationServiceFactory {
    public static VeiculoService getVeiculoService() {
        return new VeiculoServiceImpl();
    }
}

Contexto transacional

A abordagem acima é interessante, mas as operações de cada serviço não são executadas sob contexto transacional. Isto é, se tivermos uma operação que precise realizar duas ou mais instruções de persistência de dados, uma eventual falha ocorrida em uma dessas instruções não cancela as anteriores. Isso pode acarretar em estado inconsistente dos dados. Precisamos então aplicar uma solução que permita que as operações dos serviços executem sob contexto transacional.

Há várias soluções para o problema:

  • Usar Spring;
  • Escrever um aspecto;
  • Usar o padrão Proxy.

O objetivo deste artigo é explorar o padrão Proxy e a API de proxies dinâmicos do Java para aplicar um contexto transacional para todos os serviços da aplicação. Será o que desenvolveremos na parte 2.

Até lá!

06/06/2008

Enrolação de dependências – parte III

Arquivado em: design patterns — Tags:, , — tnaires @ 23:49

Finalmente, a parte final deste artigo!

Antes de prosseguir, leia: http://cabritin.wordpress.com/2008/03/07/enrolacao-de-dependencias-parte-ii/

Observe novamente a figura publicada na parte 1:

O diagrama ilustra uma relação um-para-muitos entre empresa e funcionário, este podendo ser um gerente ou um empregado.

Vamos traduzir este diagrama em um pouco de código. Inicialmente, poderíamos implementá-lo da seguinte maneira:

public class Empresa {
    private List<Funcionario> funcionarios;

    public Empresa() {
        funcionarios = new ArrayList<Funcionario>();
    }

    public void addGerente() {
        funcionarios.add(new Gerente()); // Linha 9
    }

    public void addEmpregado() {
        funcionarios.add(new Empregado()); // Linha 13
    }
}

public interface Funcionario {

}

public class Empregado implements Funcionario {
    // Construtores, atributos, métodos, etc
}

public class Gerente implements Funcionario {
    // Construtores, atributos, métodos, etc
}

Há algum problema nessa implementação? Aparentemente, não. Ela está bonitinha, usando polimorfismo, inversão de dependências (lembra o que é?) e tudo o mais. Mas veja só: a classe Empresa está instanciando diretamente as classes Gerente e Empregado (linhas numeradas). Tá, mas e qual o problema nisso? Ora, simples: se por acaso os construtores dessas classes mudarem, precisaremos modificar também as linhas 9 e 13. Agora, imagine se eu tivesse 50 classes, todas dependendo de Empregado e Gerente! Ia sobrar pro estagiário fazer a modificação em todas elas…

Mas vamos facilitar a vida do estagiário. Vamos tentar aplicar Inversão de Controle à situação.

O que queremos, então? Queremos evitar que Empresa instancie Empregado e Gerente diretamente; queremos diminuir o acoplamento entre as classes. A criação das instâncias é a responsabilidade que queremos inverter, ou seja, deixar para outra entidade fazê-lo.

Resumindo: a classe Empresa não mais criará as instâncias; ela as receberá já criadas. Como? Através dos métodos addEmpregado() e addGerente(). Vamos modificá-la então!

public class Empresa {
    private List<Funcionario> funcionarios;

    public Empresa() {
        funcionarios = new ArrayList<Funcionario>();
    }

    public void addFuncionario(Funcionario f) {
        funcionarios.add(f);
    }
}

Nossa! A classe Empresa ficou totalmente independente dos tipos concretos de Funcionario. Ela nem sabe mais que eles existem! O código cliente que utilizar as classes de domínio usará a classe como se segue:


Empresa e = new Empresa();
e.addFuncionario(new Gerente());
e.addFuncionario(new Empregado());

Ou seja, os funcionários são agora injetados dentro da empresa através do método addFuncionario(). Espere um pouco, você disse injetados?

Sim. Utilizamos um método que serve para passarmos para a (injetarmos na) classe Empresa as instâncias (dependências) de que ela precisa – neste caso, os funcionários de uma empresa. Invertemos o controle da instanciação dos objetos para o código cliente. Isto é injeção de dependências.

Há outras formas de injetar dependências em uma classe, como por exemplo fazê-lo por meio de um construtor (passando a dependência como argumento). E há também outras formas de instanciar os objetos de que sua aplicação precisa: frameworks como o Spring e o PicoContainer implementam containers que cuidam do processo de instanciação. Se não quiser utilizar um desses containers, um Factory Method resolve seu problema muito elegantemente.

Para encerrar, sugiro fortemente que você leia o artigo do Martin Fowler sobre o assunto. Estes posts não têm a intenção de substituí-lo: serve apenas para dar uma idéia geral.

Até mais.

07/03/2008

Enrolação de dependências – parte II

Arquivado em: design patterns — Tags:, , , , — tnaires @ 23:15

Antes de prosseguir, leia: http://cabritin.wordpress.com/2008/03/06/enrolacao-de-dependencias-parte-i/

Inversion of Control – IoC (inversão de controle)

Podemos definir inversão de controle como sendo simplesmente a transferência de uma ou mais responsabilidades para uma entidade exterior, que decidirá o momento e a ordem de ocorrência dos eventos inerentes a essas responsabilidades. Esse princípio já existe há muito tempo, e não se restringe somente ao mundo da computação.

Por exemplo, se você tem uma conta pra pagar, você se encaminha ao banco e paga. Ou seja, é sua responsabilidade controlar o evento “pagar minha conta”, e é você quem toma a decisão do momento em que deseja pagá-la. Porém, se você não tem tempo e pede para sua irmã efetuar o pagamento para você, você transferiu a responsabilidade sobre o evento “pagar minha conta” para ela. Assim, ela é quem vai tomar a decisão do momento de pagar a conta, lhe devolvendo o comprovante de pagamento.

Uma expressão famosa que ilustra a IoC é enunciada pelo princípio de Hollywood: “don’t call us, we call you”.

Dentro da computação, uma aplicação do conceito de inversão de controle pode ser encontrada em ferramentas baseadas em programação orientada a eventos, como o Delphi e o Visual Basic. Um programa orientado a eventos consiste, muito simploriamente, em um laço principal com duas seções: detecção e tratamento de eventos:

main()
    repita
        // Detecta eventos registrados pelo programador
        detecte_eventos()
        // Executa os eventos registrados
        trate_eventos()
    fim
fim

Quando desenvolvemos aplicações gráficas usando as IDEs referenciadas, utilizamos um framework de criação e gerenciamento de janelas e eventos (no Delphi para Win32, por exemplo, esse framework é o VCL, que significa Visual Component Library) , e esse framework fica responsável por executar o laço acima. Tudo o que precisamos fazer é definir os eventos em nosso programa e registrá-los; nós não somos mais responsáveis por executá-los. As IDEs fornecem inúmeros recursos para facilitar o registro desses eventos.

Note que, se implementarmos o laço por nós mesmos, não estamos invertendo controle de coisa alguma! Utilizar programação orientada a eventos não implica necessariamente em utilizar inversão de controle. Para isso, devemos usar alguma entidade externa – um framework, ou uma biblioteca – que execute o laço para nós e cuide das questões inerentes à detecção e tratamento de eventos.

Podemos encontrar outra aplicação de inversão de controle no paradigma orientado a objetos. Sim, estamos falando da injeção de dependências, um tipo de inversão de controle onde a responsabilidade a ser “invertida” é o processo de obter dependências. Será o tema da próxima parte deste artigo, onde retomaremos o exemplo desenvolvido na primeira.

Até lá.

06/03/2008

Enrolação de dependências – parte I

Arquivado em: design patterns — Tags:, , — tnaires @ 01:03

Uma das metas que mais se busca em orientação a objetos é diminuir o acoplamento entre os componentes da aplicação (componentes aqui são classes, pacotes, camadas, etc). E uma das formas mais eficientes de se fazer isso é utilizando injeção de dependências. Mas como toda boa prática que se torna popular, ela não podia deixar de gerar confusão entre aqueles que tentam utilizá-la. E também não podiam deixar de aparecer os “entendidos no assunto”: vomitam as palavras sem nem saber o que é e para quê serve esse recurso.

As expressões que estão na boca do povo nem sempre são as mais adequadas. Muitos se referem à prática em questão como “inversão de dependências”. Depois aparece outro que tenta corrigir, dizendo que “inversão de dependências não existe”. E chega outro falando de uma tal de “inversão de controle”. No final das contas, muitos acabam achando que as três expressões são sinônimas.

Pois bem. Vamos tentar desmistificar as coisas!

Inversão de dependências

Vamos supor que estamos desenvolvendo um sistema de cadastro de funcionários de uma empresa, onde os funcionários podem ser de dois tipos: gerentes e empregados.

Tentaremos uma primeira abordagem, ilustrada pelo diagrama de classes abaixo. De acordo com ele, uma empresa possui um ou mais gerentes e um ou mais empregados.

Diagrama de classes para a primeira abordagem.

Na figura, podemos verificar que a classe Empresa depende claramente de classes concretas, que são Gerente e Empregado. Ou seja, sempre que quisermos uma instância de Gerente na classe Empresa, teremos que obtê-la usando new Gerente(). Isso tem um lado ruim, pois se essas classes mudarem a forma como são instanciadas (modificações nos parâmetros dos construtores, por exemplo), teremos fatalmente que mexer no código da classe Empresa. Sem falar nas alterações decorrentes de um novo tipo de funcionário sendo adicionado.

Diante deste cenário, vamos enunciar o princípio da inversão de dependências:

“Componentes de alto nível não devem depender de componentes de baixo nível. Ambos devem depender de abstrações.”

Componentes de alto nível são assim chamados porque seu comportamento depende de outros componentes, os de baixo nível. No diagrama acima, Empresa é um componente de alto nível, enquanto Gerente e Empregado são de baixo nível.

E agora, como aplicar esse princípio ao diagrama acima? Simples. Posicione uma abstração entre os componentes de alto nível e os de baixo nível. Assim, ambos dependerão de abstrações:

Diagrama de classes para a segunda abordagem.

E pronto! O princípio da inversão de dependências está aplicado. Mas qual a vantagem? Uma delas é que, a partir de agora, a classe Empresa não conhece nada sobre as implementações de Funcionario; sabe apenas que lida com funcionários, não importando se são gerentes ou não. Ou seja, desacoplamento.

Mas ainda temos um problema. Antes, quando Empresa dependia de funcionários concretos, eu os instanciava diretamente usando o operador new. E agora? A inclusão dessa interface não retirou o meu problema; eu ainda preciso instanciar os funcionários usando new. E isso significa dizer que as classes ainda estão acopladas!

Ahhhhhhhh, garotinho… É exatamente nesse ponto que entra a Injeção de Dependências. Nós não criaremos as instâncias; alguém as criará para nós. Mas isso é assunto para a segunda parte desse artigo.

Até lá.

06/12/2007

O pacote java.io e o padrão Decorator

Arquivado em: design patterns — Tags:, , , , — tnaires @ 23:08

Ninguém discorda que aprender padrões de projeto é fundamental para ser um bom desenvolvedor. À medida que conhecemos programação orientada a objetos, percebemos o quanto é importante dominarmos bem esse assunto. Acredito que todos começam a estudar da mesma forma: pegando um livro com os padrões catalogados e tentando entendê-los, um a um.

A literatura de referência é o livro da Gangue dos Quatro. Não sei se todos concordarão comigo, mas achei o texto um pouco complicado para iniciantes. Li, reli e re-reli vários padrões, e quando não ficava sem entender BULHUFAS, acabava mais confuso do que antes de iniciar a leitura… A experiência continuou se repetindo para vários outros textos, até que conheci o livro da série Head First.

De cara, achei a leitura bastante agradável! Comecei estudando um dos vários padrões que não tinha conseguido entender: o Decorator. O capítulo que trata desse padrão aborda um exemplo de modelagem, enumera seus problemas, e propõe a utilização do Decorator para contorná-los. Finalmente, expõe um caso de utilização desse padrão na API da linguagem Java: as classes do pacote java.io.

Se você já tentou estudar entrada/saída com Java, provavelmente achou a implementação muuuuuito complicada, com todas aquelas classes que pareciam não ter responsabilidades bem definidas. Recomendo fortemente que você abra o capítulo 3 do livro de Design Patterns da série Head First. Uma vez entendido o padrão do qual trata esse capítulo, você nunca mais olhará o pacote java.io com os mesmos olhos, garanto!

Clique aqui para visualizar um diagrama que ilustra a utilização do padrão Decorator na API de entrada/saída da linguagem Java.

Blog no WordPress.com.