Back-End

14 fev, 2008

Padrões de Projeto PHP – Abstract Factory

Publicidade

Salve, salve leitores do iMasters,

Iremos continuar com nossa seqüência de artigos sobre Padrões de Projetos em PHP, e para essa semana escolhemos o Abstract Factory.

O Abstract Factory

Durante o desenvolvimento de aplicações doutrinadas pelo paradigma de Orientação a Objetos, Analistas e Programadores podem se deparar com a necessidade de simplificar a criação (leia-se instanciação) de alguns objetos. Talvez o objeto precise de um número detalhado de passos para sua criação e que isso seria duplicado cada vez que precisássemos de uma instancia sua;

Difícil de entender dessa forma. Nada melhor que um exemplo.

Imagine que nossa aplicação necessite acessar a base de dados no banco MySQL e TAMBÉM acessar dados no banco PostgreSQL.

Para criar a conexão com cada banco desses (MySql e PostgreSql) é necessário um conjunto de diretivas, como URL, usuário, senha, entre outros.

Exemplo de conexão com MySQL :

$conexao = mysql_pconnect("localhost","root","senha") or die("Erro ao conectar");

Não concordam comigo que seria altamente tedioso e impraticável se repetissimos essa linha de comando toda vez que precisassemos de uma conexão com o MySql?

E se um dia precisássemos alterar o usuário e/ou a senha de acesso ao banco?

O CAOS estaria formado, e teríamos que procurar por todos os arquivos de código que executassem a conexão para alterarmos no “braço” o código.

E percebam que estou somente tratando com a conexão MySql, quando nossa aplicação pretende acessar TAMBÉM dados do PostgreSQL.

É… realmente.

E qual seria a solução?

Abstract Factory na cabeça!!!

Nome do Padrão: ABSTRACT FACTORY

Problema: Como construir um conjunto de classes de mesma família de forma que a aplicação venha sofrer pouco impacto em mudanças?

Solução: Utilizamos uma família de Fábricas com o intuito de instanciar corretamente Família de Objetos de forma transparente para a aplicação. Isso é o ABSTRACT FACTORY.

Passamos a responsabilidade de criação de uma família de objetos para classes denominadas de Fábricas. Essas classes serão responsáveis por instanciar os objetos que precisamos e da forma correta. Esse é o principio de uma Fábrica de Objetos.

Caso alguma alteração venha a ser feita no momento da criação, por exemplo, a mudança de senha da nossa conexão, basta efetuarmos a modificação na classe e todas a aplicação responderá a mudança sem nenhum impacto e custo praticamente zero.

O Diagrama de Classes abaixo, explicita a idéia:

Diagrama de ClassesDiagrama de Classes

O Abstract Factory utiliza de forma intensa o principio de Polimorfismo, permitindo que a aplicação seja totalmente adaptável às mudanças decorrentes durante o desenvolvimento de forma transparente.

Iremos implementar a necessidade de conexão com diversos banco de dados (MySQL e PostgreSQL), além de permitir a inclusão de outros, quando necessário.

Vamos lá!

Primeiramente criaremos nossa Abstract Factory; Uma classe abstrata contendo o método de instanciação e que deverá ser sobrescrito em suas classes filhas.

A chamaremos de Factory_Abstract_BD



abstract class Factory_Abstract_BD {
  
    protected function __construct() {
        
    }
 //Metodo de instaciação
    abstract public function criarInstancia();
 
}

Marcamos o método criarInstancia como abstract, dessa forma forçamos as classes filhas a sobrescreverem esse método responsável pela criação de objetos de conexão.

Criaremos agora uma fábrica “concreta” que herdará de Factory_Abstract_BD, e será responsável por criar objetos de conexão com o MySQL;

Por simplicidade, retiramos a família de objetos de conexão (classe DAO), do qual objetos do tipo MySQL seriam herdados.

O nome da classe será Factory_Abstract_BD_Mysql.

class Factory_Abstract_BD_Mysql extends Factory_Abstract_BD {
 
    public function __construct() {
        parent::__construct();
    }
 
    public function criarInstancia() {
        $db = new  MySQL ("user","senha");//Classe criada e omitida sua implementação por simplicidade
        return $db;
    }
 
}

Pronto!

Temos a primeira fábrica responsável por criar conexões com o MySQL.

Se precissarmos modificar a forma como os objetos são instanciados, criando por exemplo um pool de objetos, ou mudando a senha ou qualquer outra coisa, bastar alterarmos essa classe e toda a aplicação será alterada com transparência e sem custo.

Vamos adicionar uma outra fábrica de objetos, dessa vez para conexões como o PostgreSQL.

Lembro que estaremos omitindo a implementação da classe PostgreSQL.

Tanto a classe PostgreSQL quanto a classe MySQL devem herdar de uma mesma classe mãe, contendo métodos abstratos de inclusão, exclusão, etc (ver Diagrama de Classe acima).

Chamaremos a fábrica do PostgreSQL sbiamente de Factory_Abstract_BD_PostgreSQL.

class Factory_Abstract_BD_PostgreSQL extends Factory_Abstract_BD {
 
    public function __construct() {
        parent::__construct();
    }
 
    public function criarInstancia() {
        $db = new  PostgreSQL ("user","senha");//Classe criada e omitida sua implementação por simplicidade
        return $db;
    }
 
}

Resta somente utilizarmos as fábricas.

Criaremos uma classe que recebe como parâmetro uma classe de fábrica. Essa classe efetuará uma consulta SQL.

Chamaremos essa classe de ExecutaFabrica.

class ExecutaFabrica {
 
    public function __construct() {
    }
 
    public function executa($fabrica) {
        $objetoBanco  = fabrica->criarInstancia();//Não sabe qual fábrica foi passada
        $objetoBanco->executa("insert into usuario(logim,senha) values("usuario","senha")");

   }
 
}

Também criaremos uma classe de teste, chamada de ExecutaTeste, que criará as duas Fábricas e passará para um objeto da classe ExecutaFabrica.

class ExecutaTeste {
 
    public function __construct() {
    }
 
    public function  main() {
        $fabricaMySql = new Factory_Abstract_BD_MySQL();
        $fabricaPostgreSql = new Factory_Abstract_BD_PostgreSQL();

$objeto = new ExecutaFabrica();
$objeto->executa($fabricaMySql);//Executando insert em MySql

$objeto->executa($fabricaPostgreSql);//Executando insert em PostgreSql


   }
 
}

Note que a classe ExecutaFabrica não sabe qual banco de dados está trabalhando, ou seja, não sabe qual o tipo concreto da fábrica passada. A aplicação tornou-se adaptável a mudanças de forma elegante.

O Padrão de Projeto Abstract Factory é um padrão poderoso e que deve ser utilizado com cautela, pois como podemos ver, a inclusão de novos objetos no sistema irá ocasionar na criação de diferentes fábricas e a necessidade de crescimento no número de classes em seu projeto.