PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Wzorzec Factory Method – Simple Factory, GoF, auto-generowane fabryki Magento 2

by Henryk Tews / wtorek, 10 grudnia 2019 / Opublikowano w Wzorce projektowe

Operator new w kodzie produkcyjnym to sygnał ostrzegawczy. Klasa tworząca instancje innych klas bezpośrednio jest z nimi silnie sprzężona – trudno ją testować, trudno rozszerzać. Factory Method to wzorzec, który deleguje odpowiedzialność za tworzenie obiektów do dedykowanych klas. W Magento 2 fabryki są wszechobecne – i generowane automatycznie.

Problem ze słowem kluczowym new

<?php

class OrderProcessor
{
    public function process(array $data): void
    {
        // Silne sprzężenie - nie możesz podmienić EmailNotifier w teście
        $notifier = new EmailNotifier();
        $logger   = new FileLogger('/var/log/orders.log');

        // ... logika procesowania
        $notifier->send($data['email'], 'Zamówienie przyjęte');
        $logger->log('info', 'Order processed');
    }
}

Testowanie tej klasy wymaga realnego systemu plików i serwera SMTP. Factory Method pozwala oddzielić logikę tworzenia od logiki biznesowej.

Simple Factory – punkt wejścia

Zanim przejdziemy do pełnego Factory Method, warto zobaczyć prostszą wersję – Simple Factory. To jeszcze nie wzorzec GoF, ale często wystarczy:

<?php

interface NotifierInterface
{
    public function send(string $recipient, string $message): void;
}

class EmailNotifier implements NotifierInterface
{
    public function send(string $recipient, string $message): void
    {
        // wysyłka emaila
    }
}

class SmsNotifier implements NotifierInterface
{
    public function send(string $recipient, string $message): void
    {
        // wysyłka SMS
    }
}

class SlackNotifier implements NotifierInterface
{
    public function send(string $recipient, string $message): void
    {
        // powiadomienie Slack
    }
}

// Simple Factory - centralizuje logikę tworzenia
class NotifierFactory
{
    public function create(string $type): NotifierInterface
    {
        return match ($type) {
            'email' => new EmailNotifier(),
            'sms'   => new SmsNotifier(),
            'slack' => new SlackNotifier(),
            default => throw new \InvalidArgumentException("Unknown notifier: {$type}"),
        };
    }
}

// Użycie
$factory  = new NotifierFactory();
$notifier = $factory->create('email');
$notifier->send('jan@example.com', 'Zamówienie przyjęte');

Factory Method – wzorzec GoF

Właściwy Factory Method przenosi decyzję o tworzeniu obiektu do klas potomnych. Klasa bazowa definiuje interfejs fabryki, podklasy decydują co tworzyć:

<?php

// Abstrakcyjna klasa z factory method
abstract class OrderHandler
{
    // Factory method - podklasy implementują
    abstract protected function createNotifier(): NotifierInterface;

    // Logika biznesowa używa notifiera bez wiedzy o jego typie
    public function handle(array $orderData): void
    {
        $notifier = $this->createNotifier();

        // ... procesowanie zamówienia
        $notifier->send($orderData['contact'], 'Zamówienie #' . $orderData['id'] . ' przyjęte');
    }
}

// Konkretne implementacje decydują jaki notifier tworzyć
class EmailOrderHandler extends OrderHandler
{
    protected function createNotifier(): NotifierInterface
    {
        return new EmailNotifier();
    }
}

class SmsOrderHandler extends OrderHandler
{
    protected function createNotifier(): NotifierInterface
    {
        return new SmsNotifier();
    }
}

// Użycie
$handler = new EmailOrderHandler();
$handler->handle(['id' => 123, 'contact' => 'jan@example.com']);

Factory z DI – testowalny kod

W praktyce fabryki wstrzykuje się przez DI, co umożliwia podmianę w testach:

<?php

interface NotifierFactoryInterface
{
    public function create(string $type): NotifierInterface;
}

class NotifierFactory implements NotifierFactoryInterface
{
    // Rejestr dostępnych notifierów wstrzykiwany przez DI
    public function __construct(
        private array $notifiers = []
    ) {}

    public function create(string $type): NotifierInterface
    {
        if (!isset($this->notifiers[$type])) {
            throw new \InvalidArgumentException("Notifier '{$type}' not registered");
        }

        return $this->notifiers[$type];
    }
}

class OrderProcessor
{
    public function __construct(
        private NotifierFactoryInterface $notifierFactory
    ) {}

    public function process(array $orderData): void
    {
        $type     = $orderData['notification_type'] ?? 'email';
        $notifier = $this->notifierFactory->create($type);
        $notifier->send($orderData['contact'], 'Zamówienie przyjęte');
    }
}

Konfiguracja fabryki przez di.xml – rejestr notifierów przez argumenty:

<?xml version="1.0"?>
<config>
    <type name="Vendor\Module\Model\NotifierFactory">
        <arguments>
            <argument name="notifiers" xsi:type="array">
                <item name="email" xsi:type="object">Vendor\Module\Model\EmailNotifier</item>
                <item name="sms"   xsi:type="object">Vendor\Module\Model\SmsNotifier</item>
                <item name="slack" xsi:type="object">Vendor\Module\Model\SlackNotifier</item>
            </argument>
        </arguments>
    </type>
</config>

Dodanie nowego notifiera to teraz tylko nowa klasa i jedna linia w di.xml – zero zmian w istniejącym kodzie.

Auto-generowane fabryki w Magento 2

Magento 2 automatycznie generuje klasę Factory dla każdego modelu jeśli poprosisz o nią w konstruktorze z sufiksem Factory:

<?php

use Magento\Catalog\Model\ProductFactory;

class MyService
{
    public function __construct(
        private ProductFactory $productFactory
    ) {}

    public function createProduct(array $data): \Magento\Catalog\Model\Product
    {
        // create() zawsze zwraca nową instancję
        return $this->productFactory->create(['data' => $data]);
    }
}

Plik Magento\Catalog\Model\ProductFactory nie istnieje w repozytorium Magento. Jest generowany przez setup:di:compile do katalogu generated/ na podstawie klasy Product. To jeden z najczęściej używanych mechanizmów w ekosystemie Magento 2.

Podsumowanie

Factory Method oddziela logikę tworzenia obiektów od logiki biznesowej. Kod staje się łatwiejszy do testowania – możesz wstrzyknąć mock fabryki zamiast realnych implementacji. W Magento 2 auto-generowane fabryki są wszechobecne i stanowią standardowy sposób tworzenia nowych instancji modeli, eliminując bezpośrednie użycie new w kodzie produkcyjnym.

About Henryk Tews

Co możesz przeczytać następne

Factory Method + Abstract Factory – implementacje od zera, tabela różnic, Simple Factory jako alternatywa
Wzorzec Observer w PHP i system zdarzeń Magento 2
Wzorzec Flyweight – współdzielenie obiektów, cache instancji, Magento 2
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}