Simple Factory
What is a Simple Factory?
A Simple Factory encapsulates object creation logic in a single method. It's not a formal GoF pattern but widely used.
namespace Vendor\Payment\Factory;
use Vendor\Payment\Model\Gateway;
class PaymentGatewayFactory
{
public function create(string $type): GatewayInterface
{
return match ($type) {
'stripe' => new StripeGateway(
$this->config->getStripeKey()
),
'paypal' => new PayPalGateway(
$this->config->getPayPalClientId(),
$this->config->getPayPalSecret()
),
'bank_transfer' => new BankTransferGateway(),
default => throw new \InvalidArgumentException(
"Unknown payment gateway: {$type}"
),
};
}
}
// Usage
$gateway = $factory->create('stripe');
$gateway->charge(29.99);
When to Use Simple Factory
- Creating objects based on configuration (payment methods, shipping carriers)
- The creation logic is simple (2-5 branches)
- You don't need multiple factory implementations
Factory Method Pattern
What is Factory Method?
Factory Method defines an interface for creating objects but lets subclasses decide which class to instantiate.
namespace Vendor\Catalog\Export;
// Abstract creator
class AbstractProductExporter
{
abstract protected function createFormatter(): FormatterInterface;
public function export(array $products): string
{
$formatter = $this->createFormatter();
return $formatter->format($products);
}
}
// Concrete creators
class CsvProductExporter extends AbstractProductExporter
{
protected function createFormatter(): FormatterInterface
{
return new CsvFormatter();
}
}
class JsonProductExporter extends AbstractProductExporter
{
protected function createFormatter(): FormatterInterface
{
return new JsonFormatter();
}
}
When to Use Factory Method
- Subclasses need to decide which object to create
- You want to localize creation logic in subclasses
- The framework controls extension points
Abstract Factory Pattern
What is Abstract Factory?
Provides an interface for creating families of related objects without specifying concrete classes.
namespace Vendor\Theme\Factory;
interface ComponentFactoryInterface
{
public function createHeader(): HeaderInterface;
public function createFooter(): FooterInterface;
public function createSidebar(): SidebarInterface;
}
// Desktop family
class DesktopComponentFactory implements ComponentFactoryInterface
{
public function createHeader(): HeaderInterface
{
return new DesktopHeader(); // Wide, full navigation
}
public function createFooter(): FooterInterface
{
return new DesktopFooter(); // Multi-column footer
}
public function createSidebar(): SidebarInterface
{
return new DesktopSidebar(); // Fixed sidebar
}
}
// Mobile family
class MobileComponentFactory implements ComponentFactoryInterface
{
public function createHeader(): HeaderInterface
{
return new MobileHeader(); // Hamburger menu
}
public function createFooter(): FooterInterface
{
return new MobileFooter(); // Simplified footer
}
public function createSidebar(): SidebarInterface
{
return new MobileSidebar(); // Slide-out drawer
}
}
// Usage: client code uses the interface
function renderPage(ComponentFactoryInterface $factory): void
{
$header = $factory->createHeader();
$footer = $factory->createFooter();
$sidebar = $factory->createSidebar();
// Render page with consistent component family
}
The client doesn't know if it's rendering desktop or mobile — the factory family ensures consistency.
Magento's Auto-Generated Factories
How Magento Factories Work
Magento automatically generates factory classes for any injectable class. You don't write them — they're generated in var/di/.
namespace Vendor\Catalog\Model;
// Magento auto-generates this factory
class ProductFactory
{
public function __construct(
private \Magento\Framework\ObjectManager\ObjectManager $objectManager,
private string $instanceName = 'Magento\Catalog\Model\Product'
) {}
public function create(array $data = []): Product
{
return $this->objectManager->create($this->instanceName, $data);
}
}
Using Magento Factories
namespace Vendor\Import\Model;
class ProductCreator
{
public function __construct(
private \Magento\Catalog\Model\ProductFactory $productFactory,
private \Magento\Catalog\Api\ProductRepositoryInterface $productRepo
) {}
public function createProduct(array $data): \Magento\Catalog\Api\Data\ProductInterface
{
// Factory creates new instance with constructor args
$product = $this->productFactory->create([
'data' => $data,
]);
$product->setSku($data['sku']);
$product->setName($data['name']);
$product->setPrice($data['price']);
return $this->productRepo->save($product);
}
}
Why Factories Exist in Magento
Magento uses the Object Manager to create objects with complex dependency graphs. Factories:
- Encapsulate creation logic — constructor args are resolved automatically
- Create new instances on demand — unlike DI which shares instances
- Support runtime data — pass different data for each new object
// DI gives you ONE shared instance
public function __construct(
private ProductRepositoryInterface $productRepo // one instance
) {}
// Factory gives you NEW instances each time
public function __construct(
private ProductFactory $productFactory // creates new Products
) {}
Quiz
1. What is the key difference between Factory Method and Abstract Factory?
2. When should you use Magento's auto-generated factories instead of direct DI?
3. How does Magento generate factory classes?
Flashcards
Question
What does a Simple Factory do?
Click to reveal answer
Answer
Encapsulates object creation in a single method based on input type
Question
What is the Factory Method pattern?
Click to reveal answer
Answer
Subclasses decide which class to instantiate via an abstract creation method
Question
What is an Abstract Factory?
Click to reveal answer
Answer
Creates families of related objects without specifying concrete classes
Question
When to use Magento factories vs DI?
Click to reveal answer
Answer
Factories for new instances with runtime data; DI for shared dependencies
Revision Notes
Key Takeaways
- 1. Simple Factory: one method, switch-based creation
- 2. Factory Method: subclasses decide which class to create
- 3. Abstract Factory: creates families of related objects
- 4. Magento auto-generates factories for injectable classes
- 5. Factories = new instances on demand; DI = shared instances
Interview Tips
- • Know the difference between all three factory variants
- • Explain when Magento factories are necessary vs over-engineering
- • Give a real example: ProductFactory for creating products during import
Cheat Sheet
Simple Factory → create(type) with switch/match
Factory Method → abstract createProduct(); subclasses override
Abstract Factory → createHeader() + createFooter() + createSidebar()
Magento Factory → auto-generated, creates new instances via ObjectManager
Use when: creating multiple objects with different runtime data
Skip when: DI gives you the shared instance you need