-2

Série Design Patterns com PHP: I I- Factory

criado por Adler Medrado em 03/09/2006 7:42pm
Vou tentar tornar este artigo bastante prático, para isso iremos criar uma interface e algumas classes.

A interface abaixo será implementa por algumas classes posteriormente.

Portanto, supondo que exista a interface IBanco:

<?php
Interface IBanco 
{
    public function connect();
}
?>

A interface IBanco define o método connect() que deverá ser comum a todas as classes que a implementarem.

Vamos agora, criar mais três classes:

A primeira será a classe BancoMysql que será responsável pela comunicação com o SGBDR mySQL, a segunda será a classe BancoPostgres, que será responsável pela comunicação com o SGBDR PostgreSQL e por fim, a classe BancoOracle, que se comunicará com o SGBDR ORACLE.

BancoMysql.php:

<?php
include_once ‘Ibanco.php’;
class BancoMysql() implements IBanco 
{
    public function connect() 
    {
        return new PDO('mysql:host=localhost;dbname=banco','root','');
    }
}
?>

BancoPostgres.php:

<?php
include_once ‘Ibanco.php’;
class BancoPostgres() implements IBanco 
{
    public function connect() 
    {
        return new PDO('pgsql:host=localhost port=5432 dbname=banco user=username password=senha ');
    }
}
?>

BancoOracle.php:

<?php
include_once ‘Ibanco.php’;
class BancoOracle() implements IBanco 
{
    public function connect() 
    {
        return new PDO(’OCI:dbname=accounts;charset=UTF-8&#8242;, ‘username’, ’senha’);
    }
}
?>

Utilizamos a palavra reservada implements para informar que as classes acima implementam a interface IBanco.

Agora vamos criar a classe Factory que nos retornará um objeto de uma dessas classes sem que o usuário que está utilizando estas classes precise saber o nome real da classe.

Vejamos então a implementação desta classe:

<?php
include_once ‘BancoMysql.php’;
include_once ‘BancoPostgres.php’;
include_once ‘BancoOracle.php’;
class BancoFactory 
{
    public function factory($banco) 
    {
        switch ($banco) {
            case “mysql”:
                return new BancoMysql();
            break;

            case “postgres”:
                return new BancoMysql();
            break;

            case “oracle”:
                return new BancoMysql();
            break;
        }
    }
}
?>

Na classe acima, de acordo com o parâmetro passado, é retornada uma instância de sua classe respectiva e se um dia houver uma mudança qualquer, por exemplo no nome da classe, você só precisará mudar em um lugar, na classe Factory.

Agora vamos executar esta classe:

<?php
include_once ‘BancoFactory.php’;

$bancoFactory = new BancoFactory();

// Criando instância da classe BancoMysql
$connMysql = $bancoFactory->factory(“mysql”);
print_r($connMysql->connect());

// Criando instância da classe BancoPostgres
$connPostgres = $bancoFactory->factory(“postgres”);
print_r($connPostgres->connect());

// Criando instância da classe BancoOracle
$connOracle = $bancoFactory->factory(“oracle”);
print_r($connOracle->connect());
?>

Espero que este artigo tenha ajudado a esclarecer sobre o pattern Factory.

adler medrado
http://adler.neshertech.net
adler@neshertech.net

Referências:

PDO – Foi utilizado PDO para criar objetos referentes a cada banco.
http://www.php.net/pdo

Comentários:

Mostrando 1 - 7 de 7 comentários
Marcelo Veras disse:
Atenção Programadores PHP / MySQL

Tenho uma consultoria que atende empresas em toda a América Latina, tenho como principais clientes a Alcatel e a Ford. Uma das principais ferramentas de minha empresa é baseada em PHP/MySQL (http://www.workforcesys.com) e minha empresa precisa a cada venda de um profissional para customizá-la. Enviem seus CV's para:
marcelo.veras@workforcesys.com

Não importa o estado onde vc more (temos projetos no Brasil todo e para fora do Brasil inclusive)

É importante possuir alguma experiência em implementação de sistemas de gestão e habilidade para aplicar treinamentos aos usuários. Desejável disponibilidade para viagens.
24/11/2006 10:50am (~17 anos atrás)

Pessoal
24/10/2006 8:35am (~17 anos atrás)

Adler Medrado disse:
Olá a todos.

Primeiramente, agradeço a todos pelas manifestações.

Bom vamos lá.
Matheus, realmente no switch existe um erro. Em cada opção do bloco switch deve ser instânciada a classe referente ao banco desejado.
Apesar de rever o artigo antes de publicar este erro passou despercebido. Desculpe.

Sobre a implementação da interface em cada classe, é necessário porque cada classe precisa implementar os métodos contidos naquela interface. O erro ocorreria se você não implementasse algum método contido na interface na classe de banco.


Espero ter ajudado.

adler medrado
http://adler.neshertech.net
adler@neshertech.net
18/09/2006 11:08am (~17 anos atrás)

Adler,

Primeiramente quero parabeniza-lo pelo grande apoio que esta dando a todos postando essas matérias sobre Designer Patterns. É uma grande vantagem saber sobre os Padrões de Designer de Software. O mercado exige muito em relação essa abordagem e particularmente está acrescentando bastante conhecimento a minha pessoa.

Tenho algumas duvidas em relação ao seu código de exemplo do Factory.

Porque devo implementar a interface IBanco em todas as classes de conexão? A classe BancoFactory geraria um erro ao instanciá-la não estando as classes de conexão com as interfaces implementadas?

Também não entendi porque que no switch da classe BancoFactory é instanciado, independente do case, sempre o objeto BancoMysql() e não os outros objetos referentes a classes de conexão com outros Bancos de Dados, ou seja, porque que no case "oracle" não foi instanciado o objeto BancoOracle referente a classe de Conexão com o banco Oracle? O código não esta errado?

Aguardo sua resposta. =)
18/09/2006 10:38am (~17 anos atrás)

Olá Adler,
Trabalho com design patterns há algum tempo e achei interessante sua série, porém gostaria de relatar bem resumidamente como os implemento:

No meu pacote de conexão com banco de dados, implementei o factory mas de uma forma diferente.

Criei uma classe base chamada Conexao que tinha a declaração 'implements' da interface IConexao, a partir daí todas as classes que herdavam a classe Conexao, ou seja Mysql, Postgresql e Oracle é quem realmente implementam os métodos dessa interface, mesmo não tendo a declaração implements, forçando a toda classe que herda de Conexao a implementar os métodos da sua interface, um verdadeiro contrato.

Dentro das classes filhas tenho o método singleton() e o padrão Factory retorna o singleton de cada classe.

Ex.: case 'Mysql' : return Mysql::singleton(); break;

Espero ter contribuído com seu artigo.

Abraço!
12/09/2006 7:09am (~17 anos atrás)

Click disse:
E isso aí Mark, o __autoload() é um ótimo recurso para nos livrar dos problemáticos includes.
referência: http://www.php.net/manual/pt_BR/language.oop5.autoload.php

Escreva o artigo sim, vale à pena explorar a boa implementação dos recursos do PHP 5.

Também estou preparando um artigo para o iMasters sobre implementação do MVC no PHP, com base numa framework que desenvolvemos e está começando a ser utilizada no governo, muito interessante.
06/09/2006 6:21pm (~17 anos atrás)

Olá, Adler, ultimamente eu criei uma classe para banco bem parecida, não sei muito a nomenclatura dos termos, mas é basicamente o que fez, só que utilizei alguns outros recursos:

eu criei um diretório chamado plugins, onde eu guardo as classes para os bancos(postgres, mysql, mssql...), tenho a interface, e a classe mgBanco, onde eu seleciono o banco correto, foi aí que eu mudei: não coloquei todos os includes, como plugins eu tenho: "mysql.php", "postgres.php", "mssql.php"..., quando vou instanciar eu instancio da seguinte forma:

------------
function conect()
{
$tipo = $CONFIG['type'];//aqui é passado mysql, postgres, mssql...
$conexao = new $tipo()
}
------------

na variável tipo eu tenho a classe a ser chamada, o segredo está em ser usada a função "__autoload", esta função é disparada quando o php tenta instanciar uma classe que não está inclusa:
------------
function __autoload($class_name) {
$nome = strtolower($class_name);
require_once("plugins/".$nome.".php");
}
------------
assim ele inclui somente a classe necessária para o momento...

estava até querendo fazer um artigo para esta minha classe...

até mais.
04/09/2006 5:54am (~17 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)