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 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.