ConstructiCat Logo
CodeBust.
Browse section ▾

Comparação de Factories.

Este artigo mostrará a diferença entre:

  1. Factory
  2. Método de criação
  3. Método de criação estático (ou de fábrica)
  4. Simple factory
  5. padrão Factory Method
  6. padrão Abstract Factory

Você encontra referências a esses termos por toda a web. Embora possam parecer semelhantes, todos têm significados diferentes. Muita gente não percebe isso, o que leva à confusão e a mal-entendidos.

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

1. Factory

Factory é um termo ambíguo que designa uma função, método ou classe que deveria produzir alguma coisa. Na maioria das vezes, factories produzem objetos. Mas também podem produzir arquivos, registros em bancos de dados, etc.

Por exemplo, qualquer uma destas coisas pode ser informalmente chamada de “factory”:

  • uma função ou método que cria a GUI de um programa;
  • uma classe que cria usuários;
  • um método estático que chama o construtor de uma classe de uma forma específica;
  • um dos padrões de projeto de criação.

Normalmente, quando alguém diz a palavra “factory”, o significado exato deveria ficar claro pelo contexto. Mas, se você estiver em dúvida, simplesmente pergunte. Há uma chance de que o próprio autor não saiba.

2. Método de criação

Método de criação é definido no livro Refactoring To Patterns como “um método que cria objetos”. Isso significa que todo resultado do padrão factory method é um “método de criação”, mas não necessariamente o contrário. Também significa que você pode substituir o termo “método de criação” em todos os lugares onde Martin Fowler usa o termo “factory method” em Refactoring e onde Joshua Bloch usa o termo “static factory method” em Effective Java.

Na realidade, o método de criação é apenas um invólucro em torno de uma chamada ao construtor. Ele pode simplesmente ter um nome que expressa melhor suas intenções. Por outro lado, pode ajudar a isolar seu código de mudanças no construtor. Ele poderia até conter alguma lógica específica que retornaria objetos existentes em vez de criar novos.

Muita gente chamaria esses métodos de “factory method” só porque eles produzem novos objetos. A lógica é simples: o método cria objetos e, como todas as factories criam objetos, esse método claramente deveria ser um factory method. Naturalmente, há muita confusão quando se trata do verdadeiro padrão Factory Method.

No exemplo a seguir, 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. Método de criação estático

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

Não se confunda quando alguém chamar métodos como esse de “static factory method”. Isso é só um mau hábito. O Factory Method é um padrão de projeto que depende de herança. Se você o tornar static, não poderá mais sobrescrevê-lo em subclasses, o que anula o 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 vários construtores diferentes com propósitos distintos, mas cujas assinaturas coincidem. Por exemplo, ter ao mesmo tempo Random(int max) e Random(int min) é impossível em Java, C++, C# e muitas outras linguagens. E a solução alternativa mais popular é criar vários métodos estáticos que chamam o construtor padrão e definem os valores apropriados em seguida.

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

No exemplo a seguir, o método load é um método de criação estático. Ele oferece uma forma conveniente de recuperar usuários de um banco 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. Padrão Simple factory

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

As pessoas costumam confundir as simple factories com factories em geral ou com um dos padrões de projeto de criação. Na maioria dos casos, uma simple factory é uma etapa intermediária na introdução dos padrões Factory Method ou Abstract Factory.

Uma simple factory costuma ser representada por um único método em uma única classe. Com o tempo, esse método pode ficar grande demais, então você pode decidir extrair partes dele para subclasses. Depois de fazer isso algumas vezes, você pode descobrir que tudo se transformou no clássico padrão factory method.

A propósito, se você declarar uma simple factory como abstract, ela não se transforma magicamente no padrão abstract factory.

Aqui está um exemplo de simple factory:

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 de criação que fornece uma interface para criar objetos, mas permite que as subclasses alterem o tipo de objeto que será criado.

Se você tem um método de criação na classe base e subclasses que o sobrescrevem, talvez esteja diante de um 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 de criação que permite produzir famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.

O que são as "famílias de objetos"? Por exemplo, considere este conjunto de classes: Transport + Engine + Controls. Pode haver várias variantes delas:

  1. Car + CombustionEngine + SteeringWheel
  2. Plane + JetEngine + Yoke

Se o seu programa não trabalha com famílias de produtos, então você não precisa de uma abstract factory.

E, novamente, muita gente confunde o padrão abstract factory com uma classe simple factory declarada como abstract. Não faça isso!

Posfácio

Agora que você conhece a diferença, dê uma nova olhada nos padrões de projeto: