ConstructiCat Logo
CodeBust.
Browse section ▾

Comparación de factorías.

Este artículo mostrará la diferencia entre:

  1. Factoría
  2. Método de creación
  3. Método de creación (o de factoría) estático
  4. Factoría simple
  5. El patrón Factory Method
  6. El patrón Abstract Factory

Puedes encontrar referencias a estos términos por toda la web. Aunque puedan parecer similares, todos tienen significados diferentes. Mucha gente no se da cuenta de ello, lo que genera confusión y malentendidos.

Así que intentemos descifrar la diferencia y resolver este problema de una vez por todas.

1. Factoría

El término factoría es ambiguo: designa una función, un método o una clase que se supone que produce algo. Lo más habitual es que las factorías produzcan objetos. Pero también pueden producir archivos, registros en bases de datos, etc.

Por ejemplo, cualquiera de estas cosas podría llamarse informalmente «factoría»:

  • una función o método que crea la GUI de un programa;
  • una clase que crea usuarios;
  • un método estático que llama al constructor de una clase de una determinada manera;
  • uno de los patrones de diseño creacionales.

Normalmente, cuando alguien dice la palabra «factoría», se supone que el significado exacto queda claro por el contexto. Pero si tienes dudas, simplemente pregunta. Existe la posibilidad de que el propio autor no lo sepa.

2. Método de creación

El método de creación se define en el libro Refactoring To Patterns como «un método que crea objetos». Esto significa que todo resultado del patrón Factory Method es un «método de creación», pero no necesariamente a la inversa. También significa que puedes sustituir el término «método de creación» allí donde Martin Fowler emplea el término «factory method» en Refactoring y allí donde Joshua Bloch emplea el término «static factory method» en Effective Java.

En realidad, el método de creación no es más que una envoltura alrededor de una llamada al constructor. Puede que simplemente tenga un nombre que exprese mejor tus intenciones. Por otro lado, puede ayudar a aislar tu código de los cambios en el constructor. Incluso podría contener cierta lógica que devolviera objetos existentes en lugar de crear nuevos.

Mucha gente llamaría a esos métodos «factory method» solo porque producen objetos nuevos: la lógica es sencilla: el método crea objetos y, dado que todas las factorías crean objetos, este método debería ser claramente un factory method. Naturalmente, hay mucha confusión cuando se trata del verdadero patrón Factory Method.

En el siguiente ejemplo, next es un método de creación:

class Number {
    private $value;

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

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

3. Método de creación estático

Un método de creación estático es un método de creación declarado como static. En otras palabras, se puede invocar sobre una clase y no requiere que se haya creado un objeto.

No te confundas cuando alguien llame a métodos como este «static factory method». No es más que una mala costumbre. El patrón Factory Method es un patrón de diseño que se basa en la herencia. Si lo haces static, ya no podrás extenderlo en subclases, lo que echa por tierra el propósito del patrón.

Cuando un método de creación estático devuelve objetos nuevos, se convierte en un constructor alternativo.

Puede resultar útil cuando:

  • Necesitas tener varios constructores distintos con propósitos diferentes pero cuyas firmas coinciden. Por ejemplo, tener a la vez Random(int max) y Random(int min) es imposible en Java, C++, C# y muchos otros lenguajes. Y la solución más popular es crear varios métodos estáticos que llamen al constructor por defecto y asignen después los valores adecuados.

  • Quieres reutilizar objetos existentes en lugar de instanciar otros nuevos (consulta el patrón Singleton). En la mayoría de los lenguajes de programación, los constructores tienen que devolver instancias nuevas de la clase. El método de creación estático es una solución alternativa a esta limitación. Dentro de un método estático, tu código puede decidir si crear una instancia nueva llamando al constructor o devolver un objeto existente desde alguna caché.

En el siguiente ejemplo, el método load es un método de creación estático. Proporciona una forma cómoda de recuperar usuarios de una base de datos.

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. El patrón factoría simple

El patrón de factoría simple  describe una clase que tiene un único método de creación con un gran condicional que, según los parámetros del método, elige qué clase de producto instanciar y luego devolverla.

La gente suele confundir las factorías simples con las factorías en general o con alguno de los patrones de diseño creacionales. En la mayoría de los casos, una factoría simple es un paso intermedio para introducir los patrones Factory Method o Abstract Factory.

Una factoría simple suele estar representada por un único método dentro de una única clase. Con el tiempo, este método puede volverse demasiado grande, así que podrías decidir extraer partes del método a subclases. Una vez que lo hagas varias veces, podrías descubrir que todo el conjunto se ha convertido en el clásico patrón factory method.

Por cierto, si declaras una factoría simple como abstract, no se convierte mágicamente en el patrón abstract factory.

Aquí tienes un ejemplo de factoría simple:

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. El patrón Factory Method

El patrón Factory Method  es un patrón de diseño creacional que proporciona una interfaz para crear objetos, pero permite que las subclases alteren el tipo de objeto que se creará.

Si tienes un método de creación en una clase base y subclases que la extienden, puede que estés ante el patrón 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. El patrón Abstract Factory

El patrón Abstract Factory  es un patrón de diseño creacional que permite producir familias de objetos relacionados o dependientes sin especificar sus clases concretas.

¿Qué son las «familias de objetos»? Por ejemplo, tomemos este conjunto de clases: Transport + Engine + Controls. Podría haber varias variantes de estas:

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

Si tu programa no trabaja con familias de productos, entonces no necesitas una abstract factory.

Y, una vez más, mucha gente confunde el patrón abstract factory con una clase de factoría simple declarada como abstract. ¡No hagas eso!

Epílogo

Ahora que conoces la diferencia, echa un nuevo vistazo a los patrones de diseño: