Simple Factory
The Simple Factory Pattern is a common programming idiom where
a single factory class is responsible for creating objects based on input parameters.
Simple Factory is not one of the 23 Gang of Four design patterns.
It is widely used in practice because it centralizes object creation logic
and hides the concrete class instantiation from the client.
Structure
| Role |
Example |
Responsibility |
| Factory |
PaymentFactory |
Decides which concrete product to create |
| Product |
PaymentMethod |
Defines the common interface |
| Concrete Product |
PaypalPayment, StripePayment |
Implements the product interface |
Steps
- Create a Product interface
- Implement Concrete Products
- Create a Factory class
- The factory decides which object to create based on input
classDiagram
class PaymentFactory {
+create(method): PaymentMethod
}
class PaymentMethod {
<<interface>>
+pay(amount)
}
class PaypalPayment {
+pay(amount)
}
class StripePayment {
+pay(amount)
}
PaymentMethod <|.. PaypalPayment
PaymentMethod <|.. StripePayment
PaymentFactory --> PaymentMethod : creates
The client calls the factory (like PaymentFactory) with a parameter (for example "Paypal" or "Stripe"),
and the factory decides which concrete product (like Paypal or Stripe) should be instantiated.
Example 1: Payment Factory
PaymentFactory creates the appropriate payment gateway
based on a payment method identifier.
Product Interface
| PaymentMethod.php |
|---|
| <?php
declare(strict_types=1);
namespace DesignPattern\Creational\SimpleFactory\Payment;
interface PaymentMethod
{
public function pay(float $amount): string;
}
|
Factory
| PaymentFactory.php |
|---|
| <?php
declare(strict_types=1);
namespace DesignPattern\Creational\SimpleFactory\Payment;
class PaymentFactory
{
/**
* @param string $payment
* @return PaymentMethod
* @throws \InvalidArgumentException
*/
public function create(string $payment): PaymentMethod
{
return match (strtolower($payment)) {
'paypal' => new PaypalPayment(),
'stripe' => new StripePayment(),
default => throw new \InvalidArgumentException('Payment Method not created'),
};
}
}
|
Concrete Products
Tests
| PaymentTest.php |
|---|
| <?php
declare(strict_types=1);
namespace Tests\Creational\SimpleFactory;
use DesignPattern\Creational\SimpleFactory\Payment\PaymentFactory;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(PaymentFactory::class)]
class PaymentTest extends TestCase
{
/**
* @return void
* @throws \InvalidArgumentException
*/
public function testFactoryMethod(): void
{
$paymentMethod = new PaymentFactory();
$paypal = $paymentMethod->create('paypal');
$stripe = $paymentMethod->create('stripe');
self::assertSame('Paid 100 via PayPal', $paypal->pay(100));
self::assertSame('Paid 50 via Stripe', $stripe->pay(50));
}
}
|
Example 2: Animal Factory
AnimalFactory creates different Animal objects based on a given type.
Product Interface
| Animal.php |
|---|
| <?php
declare(strict_types=1);
namespace DesignPattern\Creational\SimpleFactory\Animal;
interface Animal
{
public function speak(): string;
}
|
Factory
| AnimalFactory.php |
|---|
| <?php
declare(strict_types=1);
namespace DesignPattern\Creational\SimpleFactory\Animal;
class AnimalFactory
{
/**
* @param string $animal
* @return Animal
* @throws \InvalidArgumentException
*/
public function create(string $animal): Animal
{
return match (strtolower($animal)) {
'cat' => new Cat(),
'dog' => new Dog(),
default => throw new \InvalidArgumentException('Animal ' . $animal . ' not created'),
};
}
}
|
Concrete Products
Tests
| Cat.php |
|---|
| <?php
declare(strict_types=1);
namespace Tests\Creational\SimpleFactory;
use DesignPattern\Creational\SimpleFactory\Animal\AnimalFactory;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(AnimalFactory::class)]
class AnimalTest extends TestCase
{
/**
* @return void
* @throws \InvalidArgumentException
*/
public function testFactoryMethod(): void
{
$factory = new AnimalFactory();
$cat = $factory->create('cat');
$dog = $factory->create('dog');
self::assertSame('miau', $cat->speak());
self::assertSame('woof', $dog->speak());
}
}
|