The Factory pattern is a creational design pattern that provides an interface for creating objects but delegates the actual object instantiation to subclasses or specialized factory methods. It encapsulates the object creation logic, promoting loose coupling and flexibility in object creation. In PHP, the Factory pattern can be implemented using different approaches, such as simple factory, factory method, or abstract factory.
Simple Factory:
The simple factory, also known as the static factory, is the simplest form of the Factory pattern. It involves a single factory class responsible for creating objects based on input parameters. Here's an example:
// Product interface defines the contract for the products.
interface Product {
public function getName();
}
// Concrete products implement the product interface.
class ConcreteProductA implements Product {
public function getName() {
return 'Product A';
}
}
class ConcreteProductB implements Product {
public function getName() {
return 'Product B';
}
}
// Simple factory class that creates products based on the input.
class SimpleFactory {
public static function createProduct($type) {
switch ($type) {
case 'A':
return new ConcreteProductA();
case 'B':
return new ConcreteProductB();
default:
throw new InvalidArgumentException("Invalid product type.");
}
}
}
// Usage example:
$productA = SimpleFactory::createProduct('A');
echo $productA->getName(); // Output: Product A
$productB = SimpleFactory::createProduct('B');
echo $productB->getName(); // Output: Product B
In this example, we have a Product interface representing the contract for all products. The ConcreteProductA
and ConcreteProductB
classes implement the Product interface. The SimpleFactory
class provides a static method createProduct()
that accepts a type parameter and returns the appropriate concrete product instance based on the type.
Factory Method:
The factory method involves defining an abstract factory class with a method for creating objects. Subclasses of the abstract factory class implement the factory method to create specific product objects. Here's an example:
// Product interface defines the contract for the products.
interface Product {
public function getName();
}
// Concrete products implement the product interface.
class ConcreteProductA implements Product {
public function getName() {
return 'Product A';
}
}
class ConcreteProductB implements Product {
public function getName() {
return 'Product B';
}
}
// Abstract factory class with the factory method.
abstract class Factory {
abstract public function createProduct(): Product;
public function someOperation() {
$product = $this->createProduct();
echo $product->getName();
}
}
// Concrete factory classes implement the factory method to create specific products.
class ConcreteFactoryA extends Factory {
public function createProduct(): Product {
return new ConcreteProductA();
}
}
class ConcreteFactoryB extends Factory {
public function createProduct(): Product {
return new ConcreteProductB();
}
}
// Usage example:
$factoryA = new ConcreteFactoryA();
$factoryA->someOperation(); // Output: Product A
$factoryB = new ConcreteFactoryB();
$factoryB->someOperation(); // Output: Product B
In this example, the Product interface and the concrete product classes ConcreteProductA
and ConcreteProductB
remain the same. The difference lies in the introduction of the Factory abstract class with the createProduct()
factory method. The ConcreteFactoryA
and ConcreteFactoryB
classes extend the Factory class and implement the createProduct()
method to create specific products.
Abstract Factory:
The abstract factory involves a hierarchy of related factory classes, each responsible for creating a family of related products. It allows the creation of objects without specifying their concrete classes. Here's an example:
// Abstract product classes define the contract for the products.
abstract class AbstractProductA {
abstract public function getName();
}
abstract class AbstractProductB {
abstract public function getName();
}
// Concrete product classes implement the abstract product classes.
class ConcreteProductA1 extends AbstractProductA {
public function getName() {
return 'Product A1';
}
}
class ConcreteProductA2 extends AbstractProductA {
public function getName() {
return 'Product A2';
}
}
class ConcreteProductB1 extends AbstractProductB {
public function getName() {
return 'Product B1';
}
}
class ConcreteProductB2 extends AbstractProductB {
public function getName() {
return 'Product B2';
}
}
// Abstract factory class with factory methods for creating product families.
abstract class AbstractFactory {
abstract public function createProductA(): AbstractProductA;
abstract public function createProductB(): AbstractProductB;
}
// Concrete factory classes implement the abstract factory class.
class ConcreteFactory1 extends AbstractFactory {
public function createProductA(): AbstractProductA {
return new ConcreteProductA1();
}
public function createProductB(): AbstractProductB {
return new ConcreteProductB1();
}
}
class ConcreteFactory2 extends AbstractFactory {
public function createProductA(): AbstractProductA {
return new ConcreteProductA2();
}
public function createProductB(): AbstractProductB {
return new ConcreteProductB2();
}
}
// Usage example:
$factory1 = new ConcreteFactory1();
$productA1 = $factory1->createProductA();
$productB1 = $factory1->createProductB();
echo $productA1->getName(); // Output: Product A1
echo $productB1->getName(); // Output: Product B1
$factory2 = new ConcreteFactory2();
$productA2 = $factory2->createProductA();
$productB2 = $factory2->createProductB();
echo $productA2->getName(); // Output: Product A2
echo $productB2->getName(); // Output: Product B2
In this example, we have the abstract product classes AbstractProductA
and AbstractProductB
and their concrete implementations ConcreteProductA1
, ConcreteProductA2
, ConcreteProductB1
, and ConcreteProductB2
. The AbstractFactory
class declares factory methods for creating products of different families, and the concrete factory classes ConcreteFactory1
and ConcreteFactory2
implement these factory methods to create specific products within their families.
The Factory pattern provides a way to encapsulate object creation, promote loose coupling, and enhance code maintainability and flexibility. It allows for easy extensibility by introducing new product classes or factory implementations without affecting existing client code.