O que é um Factory Design Pattern em PHP?

88

Isso me confunde, nos termos mais simples, o que isso faz? Finja que está explicando para sua mãe ou para alguém quase que por favor.

JasonDavis
fonte
115
Minha mãe não entenderia mesmo ...
Bruno Reis
6
@JasonDavis Eu continuo respondendo suas perguntas ... Estou começando a me sentir um perseguidor.
Tyler Carter

Respostas:

175

Uma fábrica cria um objeto. Então, se você quiser construir

 class A{
    public $classb;
    public $classc;
    public function __construct($classb, $classc)
    {
         $this->classb = $classb;
         $this->classc = $classc;
    }
  }

Você não gostaria de ter que fazer o seguinte código sempre que criar o objeto

$obj = new ClassA(new ClassB, new Class C);

É aí que a fábrica entraria. Definimos uma fábrica para cuidar disso por nós:

class Factory{
    public function build()
    {
        $classc = $this->buildC();
        $classb = $this->buildB();
        return $this->buildA($classb, $classc);

    }

    public function buildA($classb, $classc)
    {
        return new ClassA($classb, $classc);
    }

    public function buildB()
    {
        return new ClassB;
    }

    public function buildC()
    {
        return new ClassC;
    }
}

Agora tudo que temos que fazer é

$factory = new Factory;
$obj     = $factory->build();

A verdadeira vantagem é quando você quer mudar de classe. Digamos que quiséssemos passar em uma classe C diferente:

class Factory_New extends Factory{
    public function buildC(){
        return new ClassD;
    }
}

ou uma nova classe B:

class Factory_New2 extends Factory{
    public function buildB(){
        return new ClassE;
    }
}

Agora podemos usar a herança para modificar facilmente como a classe é criada, para colocar um conjunto diferente de classes.

Um bom exemplo pode ser esta classe de usuário:

class User{
    public $data;
    public function __construct($data)
    {
        $this->data = $data;
    }
}

Nesta classe $dataestá a classe que usamos para armazenar nossos dados. Agora, para esta classe, digamos que usamos uma Sessão para armazenar nossos dados. A fábrica seria assim:

class Factory{
    public function build()
    {
        $data = $this->buildData();
        return $this->buildUser($data);
    }

    public function buildData()
    {
        return SessionObject();
    }

    public function buildUser($data)
    {
        return User($data);
    }
}

Agora, digamos que queremos armazenar todos os nossos dados no banco de dados, é realmente simples alterá-lo:

class Factory_New extends Factory{
    public function buildData()
    {
        return DatabaseObject();
    }
}

As fábricas são um padrão de design que usamos para controlar como colocamos os objetos juntos, e o uso de padrões de fábrica corretos nos permite criar os objetos personalizados de que precisamos.

Tyler Carter
fonte
3
Isso foi muita digitação. Agora terei que colocá-lo no meu wiki em algum momento.
Tyler Carter
1
Agradável e útil. Tiremos o chapéu para você, companheiro.
stefgosselin
1
Qual é a diferença / benefício de seu código $obj = $factory->build();mais $obj = new whateverClass();? Além disso, em outra classe (digamos classZ) que depende dos dados da classeA, onde na classeZ você usaria o método de fábrica? Você ainda está essencialmente instanciando uma classe (classZ) dentro de uma classe (classA), o que significa nenhum teste. por exemplo, a fábrica parece ser uma carga de código para fazer newpor meio de um método em vez de apenas usar new.
James,
19

Como uma fábrica da vida real, ele cria algo e o devolve.

Imagine algo assim

$joe = new Joe();
$joe->say('hello');

ou um método de fábrica

Joe::Factory()->say('hello');

A implementação do método de fábrica criará uma nova instância e a retornará.

alex
fonte
1
Bom exemplo, me surpreende como as implementações são variadas para este padrão. Quando chamado estaticamente, presumo que seja possível obter uma referência para a instância para reutilizar a mesma instância mais tarde? ou seja, $ joe = Joe :: Factory () -> diga ('olá');
stefgosselin
certamente como em 5.6 também se pode fazer (new Joe ()) -> dizer ('olá');
Pancho
12

O padrão de design de fábrica é muito bom quando você está lidando com vários recursos e deseja implementar abstração de alto nível.

Vamos dividir isso em seções diferentes.

Suponha que você tenha que implementar abstração e o usuário de sua classe não precise se preocupar com o que você implementou na definição da classe.

Ele só precisa se preocupar com o uso de seus métodos de classe.

por exemplo, você tem dois bancos de dados para o seu projeto

class MySQLConn {

        public function __construct() {
                echo "MySQL Database Connection" . PHP_EOL;
        }

        public function select() {
                echo "Your mysql select query execute here" . PHP_EOL;
        }

}

class OracleConn {

        public function __construct() {
                echo "Oracle Database Connection" . PHP_EOL;
        }

        public function select() {
                echo "Your oracle select query execute here" . PHP_EOL;
        }

}

Sua classe Factory cuidaria da criação do objeto para conexão com o banco de dados.

class DBFactory {

        public static function getConn($dbtype) {

                switch($dbtype) {
                        case "MySQL":
                                $dbobj = new MySQLConn();
                                break;
                        case "Oracle":
                                $dbobj = new OracleConn();
                                break;
                        default:
                                $dbobj = new MySQLConn();
                                break;
                }

                return $dbobj;
        }

}

O usuário só precisa passar o nome do tipo de banco de dados

$dbconn1 = DBFactory::getConn("MySQL");
$dbconn1->select();

Resultado:

MySQL Database Connection
Your mysql select query execute here

No futuro, você pode ter um banco de dados diferente, então você não precisa alterar o código inteiro, apenas precisa passar o novo tipo de banco de dados e outro código será executado sem fazer nenhuma alteração.

$dbconn2 = DBFactory::getConn("Oracle");
$dbconn2->select();

Resultado:

Oracle Database Connection
Your oracle select query execute here

Espero que isso ajude.

Shailesh Sonare
fonte
1

Em geral, uma "fábrica" ​​produz algo: no caso da Programação Orientada a Objetos, um "padrão de design de fábrica" ​​produz objetos.

Não importa se é em PHP, C # ou qualquer outra linguagem Orientada a Objetos.

Pindatjuh
fonte
1

Padrão de projeto de fábrica (padrão de fábrica) é para acoplamento fraco. Como o significado de fábrica, dados para uma fábrica (produzir dados) para o usuário final. Dessa forma, a fábrica rompe o forte acoplamento entre a fonte de dados e o processo de dados.

N Zhang
fonte
0

Esta resposta é em relação a outro post em que Daniel White disse para usar fábrica para criar a conexão MySQL usando o padrão de fábrica.

Para a conexão MySQL, prefiro usar o padrão singleton, pois você deseja usar a mesma conexão para acessar o banco de dados e não criar outra.

Marcin - user2676388
fonte
0

A abordagem clássica para instanciar um objeto é:

$Object=new ClassName();

O PHP pode criar dinamicamente um objeto a partir do nome da variável usando a seguinte sintaxe:

$Object=new $classname;

onde a variável $ classname contém o nome da classe que se deseja instanciar.

Portanto, a fatoração de objetos clássica seria semelhante a:

function getInstance($classname)
{
  if($classname==='Customer')
  {
    $Object=new Customer();
  }
  elseif($classname==='Product')
  {
    $Object=new Product();
  }
  return $Object;
}

e se você chamar a função getInstance ('Produto'), essa fábrica criará e retornará o objeto Produto. Caso contrário, se você chamar a função getInstance ('Customer'), essa fábrica criará e retornará o objeto do tipo Cliente (criado a partir da classe Customer ()).

Não há mais necessidade disso, pode-se enviar 'Produto' ou 'Cliente' (nomes exatos de classes existentes) como um valor de variável para instanciação dinâmica:

$classname='Product';
$Object1=new $classname; //this will instantiate new Product()

$classname='Customer';
$Object2=new $classname; //this will instantiate new Customer()
sbrbot
fonte
0

Para o registro, em palavras fáceis, uma fábrica como @Pindatjuh disse, retorna um objeto.

Então, qual é a diferença com um construtor? (isso faz o mesmo)

  1. um construtor usa sua própria instância.
  2. Algo que eu quero, então algo mais avançado e não quero inchar o objeto (ou adicionar dependências).
  3. O construtor é chamado quando cada instância é criada. Às vezes você não quer isso.

    Por exemplo, digamos que toda vez que eu crio um objeto da classe Account, eu leio um arquivo do banco de dados e o uso como template.

Usando o construtor:

class Account {
      var $user;
      var $pwd;
      var ...
      public __construct() {
         // here i read from the file
         // and many other stuff
      }
}

Usando a fábrica:

class Account {
      var $user;
      var $pwd;
      var ...
}
class AccountFactory {
      public static Create() {
         $obj=new Account();
         // here we read the file and more stuff.
         return $obj;
      }
Magalhães
fonte