Menu
Coddy logo textTech

Patrón Factory

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 72 de 91.

El Patrón Factory es un patrón de diseño creacional que delega la creación de objetos a una clase o método independiente. En lugar de usar new directamente en todo el código, se le pide a una fábrica que cree los objetos por ti.

Este patrón es particularmente útil cuando tienes múltiples clases relacionadas que comparten una interfaz común y quieres decidir cuál instanciar basándote en alguna condición. Considera un sistema de notificaciones que puede enviar mensajes a través de diferentes canales:

<?php
interface Notification {
    public function send(string $message): string;
}

class EmailNotification implements Notification {
    public function send(string $message): string {
        return "Email: $message";
    }
}

class SmsNotification implements Notification {
    public function send(string $message): string {
        return "SMS: $message";
    }
}

Sin una fábrica, dispersarías sentencias if y llamadas new por todas partes. La fábrica centraliza esta lógica:

<?php
class NotificationFactory {
    public static function create(string $type): Notification {
        return match($type) {
            'email' => new EmailNotification(),
            'sms' => new SmsNotification(),
            default => throw new InvalidArgumentException("Unknown type: $type")
        };
    }
}

$notification = NotificationFactory::create('email');
echo $notification->send('Hello!');

Salida:

Email: Hello!

El beneficio clave es que su código depende de la interfaz Notification, no de clases concretas. Si más adelante añade una clase PushNotification, solo tendrá que actualizar la fábrica. Todo el código que utiliza la fábrica obtiene automáticamente acceso al nuevo tipo sin necesidad de modificaciones.

challenge icon

Desafío

Fácil

Vamos a construir un sistema generador de documentos utilizando el Factory Pattern. Diferentes tipos de documentos (PDF, HTML, Texto Plano) comparten una interfaz común pero producen salidas diferentes — un escenario perfecto para centralizar la creación de objetos en una fábrica.

Organizarás tu código en cuatro archivos:

  • Document.php — Crea una interfaz Document que defina el contrato que todos los tipos de documentos deben seguir. Debe tener un único método render(string $content): string que reciba el contenido y devuelva la salida del documento formateada.
  • Documents.php — Incluye la interfaz Document y crea tres clases que la implementen:
    • PdfDocument — Su método render() devuelve "PDF: [content]"
    • HtmlDocument — Su método render() devuelve "<html>[content]</html>"
    • TextDocument — Su método render() devuelve "TXT: [content]"
  • DocumentFactory.php — Incluye el archivo Documents y crea una clase DocumentFactory con un método estático create(string $type): Document. Este método debe usar match para devolver el objeto de documento apropiado basado en el tipo:
    • "pdf" devuelve un nuevo PdfDocument
    • "html" devuelve un nuevo HtmlDocument
    • "text" devuelve un nuevo TextDocument
    • Cualquier otro tipo debe lanzar una InvalidArgumentException con el mensaje "Unknown document type: [type]"
  • main.php — Incluye el archivo DocumentFactory. Recibirás dos entradas: un tipo de documento y el contenido a renderizar.

    Usa la fábrica para crear el tipo de documento apropiado, luego llama a su método render() con el contenido e imprime el resultado.

    En una nueva línea, imprime "Factory benefit: Adding new types only requires updating the factory" para resaltar por qué este patrón es valioso.

El Factory Pattern mantiene tu código flexible — cuando necesites añadir un MarkdownDocument más adelante, solo actualizarás la fábrica mientras que todo el código existente continuará funcionando sin cambios.

Hoja de referencia

El Patrón Factory delega la creación de objetos a una clase o método independiente en lugar de usar new directamente en todo el código.

Este patrón es útil cuando tienes varias clases relacionadas que comparten una interfaz común y necesitas decidir cuál instanciar basándote en una condición.

Ejemplo con un sistema de notificaciones:

<?php
interface Notification {
    public function send(string $message): string;
}

class EmailNotification implements Notification {
    public function send(string $message): string {
        return "Email: $message";
    }
}

class SmsNotification implements Notification {
    public function send(string $message): string {
        return "SMS: $message";
    }
}

La fábrica centraliza la lógica de creación de objetos:

<?php
class NotificationFactory {
    public static function create(string $type): Notification {
        return match($type) {
            'email' => new EmailNotification(),
            'sms' => new SmsNotification(),
            default => throw new InvalidArgumentException("Unknown type: $type")
        };
    }
}

$notification = NotificationFactory::create('email');
echo $notification->send('Hello!'); // Output: Email: Hello!

Beneficios clave:

  • El código depende de la interfaz, no de las clases concretas
  • Añadir nuevos tipos solo requiere actualizar la fábrica
  • El código existente obtiene acceso automáticamente a los nuevos tipos sin necesidad de modificaciones

Pruébalo tú mismo

<?php
require_once 'DocumentFactory.php';

// Leer entrada
$type = trim(fgets(STDIN));
$content = trim(fgets(STDIN));

// TODO: Usar DocumentFactory para crear el tipo de documento apropiado
// TODO: Llamar al método render() con el contenido e imprimir el resultado
// TODO: En una nueva línea, imprimir "Factory benefit: Adding new types only requires updating the factory"

?>
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos