REDUÇÃO de Inverno

Comparação Factory

Este artigo irá mostrar as diferenças entre:

  1. Factory (Fábrica)
  2. Creation method (Método de criação)
  3. Static creation method (Método de criação estática)
  4. Simple factory (Fábrica simples)
  5. Padrão Factory Method
  6. Padrão Abstract Factory

Você pode encontrar referências a todos esses termos na web. Embora pareçam similares, eles todos têm significados diferentes. Muitas pessoas não se dão conta disso, o que leva a confusão e equívocos.

Então vamos tentar entender a diferença e resolver esse problema de uma vez por todas.

1. Factory (Fábrica)

Fábrica é um termo ambíguo que se refere a uma função, método ou classe que deve produzir alguma coisa. Mais comumente, fábricas produzem objetos. Mas elas também podem produzir arquivos, registros em bases de dados, etc.

Por exemplo, qualquer uma destas coisas pode ser casualmente referenciada como uma “fábrica”:

  • uma função ou método que cria a interface de um programa;
  • uma classe que cria usuários;
  • um método estático que chama uma classe construtora de uma certa maneira;
  • um dos padrões de projeto criacionais.

Geralmente, quando alguém diz uma palavra “fábrica”, o significado exato deve ficar claro a partir de um contexto. Mas se estiver em dúvida, apenas pergunte. Há uma chance que o autor seja ignorante.

2. Creation method (Método de criação)

O método de criação definido no livro Refatoração para Padrões como “um método que cria objetos”. Isso significa que qualquer resultado de um padrão Factory Method é um “método de criação” mas não necessariamente o inverso. Também quer dizer que você pode substituir o termo “método de criação” sempre que Martin Fowler usar o termo “método fábrica” em Refactoring e sempre que Joshua Bloch usar o termo “método fábrica estático” em Effective Java.

Na verdade, o método de criação é apenas um wrapper ao redor de uma chamada de construtor. Ele apenas tem um nome que melhor expressa suas intenções. Por outro lado, ele pode ajudar a isolar seu código de mudanças do construtor. Ele pode até conter certa lógica que retornaria objetos existentes ao invés de criar novos objetos.

Muitas pessoas chamariam tais métodos “métodos fábrica” apenas porque ele produz novos objetos: A lógica é simples: o método cria objetos e já que todas as fábricas criam objetos, esse método deve claramente ser uma método fábrica. Naturalmente, há muita confusão quando se trata do verdadeiro padrão Factory Method.

No seguinte exemplo, next é um método de criação:

class Number {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function next() {
        return new Number ($this->value + 1);
    }
}

3. Static creation method
(Método de criação estática)

O método de criação estático é um método de criação declarado como static. Em outras palavras, ele pode ser chamado em uma classe e não precisa que um objeto seja criado.

Não se confunda quando alguém chama métodos como esse de “método fábrica estático”. Isso é um mau hábito. O Factory Method é um padrão de projeto que se baseia em herança. Se você torná-lo estático, você não pode mais estendê-lo em subclasses, que é contrário ao propósito do padrão.

Quando um método de criação estático retorna novos objetos ele se torna um construtor alternativo.

Ele pode ser útil quando:

  • Você precisa ter diferentes construtores para diferentes propósitos mas as assinaturas deles coincidem. Por exemplo, tendo ambos Random(int max) e Random(int min) é possível em Java C++, C#, e muitas outras linguagens. E o modo mais popular de fazer isso é criar vários métodos estáticos que chamam o construtor padrão e configuram valores apropriados depois.

  • Você quer reutilizar objetos existentes, ao invés de instanciar novos objetos (veja o padrão Singleton). Os construtores na maioria das linguagens de programação precisam retornar novas instâncias de classe. O método de criação estático é uma alternativa a essa limitação. Dentro de um método estático, seu código pode decidir se quer criar uma instância nova chamando o construtor ou retornar um objeto existente de algum cache.

No seguinte exemplo, o método load é um método criação estático. Ele fornece uma maneira conveniente de buscar usuários de uma base de dados.

class User {
    private $id, $name, $email, $phone;

    public function __construct($id, $name, $email, $phone) {
        $this->id = $id;
        $this->name = $name;
        $this->email = $email;
        $this->phone = $phone;
    }

    public static function load($id) {
        list($id, $name, $email, $phone) = DB::load_data('users', 'id', 'name', 'email', 'phone');
        $user = new User($id, $name, $email, $phone);
        return $user;
    }
}

4. Simple factory (Fábrica simples)

O padrão fábrica simples  descreve uma classe que tem um método de criação com uma condicional grande que, baseada nos parâmetros do método, escolhe qual classe produto instanciar e então retornar.

As pessoas geralmente confundem fábricas simples com fábricas gerais ou com um dos padrões de projeto criacional. Na maioria dos casos, uma fábrica simples é uma etapa intermediária na introdução dos padrões Factory Method ou Abstract Factory.

Fábricas simples geralmente não têm subclasses. Mas após extrair subclasses de uma fábrica simples, ela começa a se parecer como um padrão Factory Method clássico.

A propósito, se você declarar uma fábrica simples como abstract, ela não se torna um padrão Abstract Factory magicamente.

Aqui temos um exemplo da fábricas simples:

class UserFactory {
    public static function create($type) {
        switch ($type) {
            case 'user': return new User();
            case 'customer': return new Customer();
            case 'admin': return new Admin();
            default:
                throw new Exception('Wrong user type passed.');
        }
    }
}

5. Padrão Factory Method

O Factory Method  é um padrão de projeto criacional que fornece uma interface para criação de objetos mas permite que subclasses alterem o tipo de um objeto que será criado.

Se você tem um método de criação na classe base e subclasses que estendem ele, você pode estar olhando para o Factory Method.

abstract class Department {
    public abstract function createEmployee($id);

    public function fire($id) {
        $employee = $this->createEmployee($id);
        $employee->paySalary();
        $employee->dismiss();
    }
}

class ITDepartment extends Department {
    public function createEmployee($id) {
        return new Programmer($id);
    }
}

class AccountingDepartment extends Department {
    public function createEmployee($id) {
        return new Accountant($id);
    }
}

6. Padrão Abstract Factory

O Abstract Factory  é um padrão de projeto criacional que permite produzir famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.

Quais são as "famílias de objetos"? Por exemplo, tome este conjunto de classes: Transporte + Motor + Controles. Pode haver muitas variantes deles:

  1. Carro + MotorCombustão + Volante
  2. Avião + Turbina + Jugo

Se o seu programa não opera com famílias de produtos, então você não precisa de um Abstract Factory.

E novamente, muitas pessoas confundem o padrão Abstract Factory com a classe fábrica simples declarada como abstract. Não faça isso!

Posfácio

Agora que você sabe a diferença, vá dar uma olhada nos padrões de projeto: