Factory - The Object Creational Pattern
Moniruzzaman Saikat

Moniruzzaman Saikat @moniruzzamansaikat

About: Always learning new stuffs....

Location:
Dhaka
Joined:
Dec 5, 2020

Factory - The Object Creational Pattern

Publish Date: Jul 15
0 0

It's a design pattern that encapsulates object creation logic so your main application code doesn’t depend on concrete class names. Just ask the factory and get what you need.

Think of the Factory Pattern as a power plug adapter. You plug in any device (Laptop, Phone, TV), and it gives you the correct current — without worrying about how it works. The Factory Pattern’s main goal is to decouple object creation from business logic, making your code flexible, testable, and easy to maintain.

Here is an example of factory pattern using a case of document exporter.

interface Exporter {
    public function export(array $data): string;
}

class PdfExporter implements Exporter {
    public function export(array $data): string {
        return "Exporting as PDF";
    }
}

class CsvExporter implements Exporter {
    public function export(array $data): string {
        return "Exporting as CSV";
    }
}

class ExportFactory {
    public static function getExporter(string $format): Exporter {
        return match($format) {
            'pdf' => new PdfExporter(),
            'csv' => new CsvExporter(),
            default => throw new Exception("Invalid export format"),
        };
    }
}

// Usage
$exporter = ExportFactory::getExporter('csv');
echo $exporter->export([]);

Enter fullscreen mode Exit fullscreen mode

Why should you use factory pattern ?

  • You want to centralize object creation
  • You want to decouple code (client doesn’t know which exact class it is using)
  • You want flexibility to change which object is created, without touching client code

Here is another example by a notification sender (Email, SMS, Push, Whatever) system:

interface Notifier {
    public function send(string $message): string;
}

class EmailNotifier implements Notifier {
    public function send(string $message): string {
        return "Sending Email: $message";
    }
}

class SMSNotifier implements Notifier {
    public function send(string $message): string {
        return "Sending SMS: $message";
    }
}

class PushNotifier implements Notifier {
    public function send(string $message): string {
        return "Sending Push Notification: $message";
    }
}

class NotificationFactory {
    public static function create(string $type): Notifier {
        return match($type) {
            'email' => new EmailNotifier(),
            'sms' => new SMSNotifier(),
            'push' => new PushNotifier(),
            default => throw new Exception("Invalid notifier type"),
        };
    }
}

// Usage
$notifier = NotificationFactory::create('sms');
echo $notifier->send('Factory pattern rocks!');

Enter fullscreen mode Exit fullscreen mode

Hahaha, Lemme tell you a story for better understand okay:

Once upon a time in a small tech town, there lived a programmer named Saikat. And halay was building an online food ordering system for a popular restaurant called "Code Crust Pizza".

But each time a customer ordered a pizza — Margherita, Pepperoni, or Veggie — Saikat's app had to do something like:

$margherita = new MargheritaPizza();
$pepperoni = new PepperoniPizza();
$veggie = new VeggiePizza();
Enter fullscreen mode Exit fullscreen mode

and you know how bad is this when in the system you do all these here and there. it's fine with 2/3 classes until the restaurant added 10 more pizza types and wanted to change the way some pizzas were baked.

oh oh oh, an idea like okay: what if I order someone to build all the things for a new pizza(all the processes in it) and it will just be used from the client codebase in a very simple way. So this is the time to build a PizzaFactory — a smart kitchen helper who knows how to prepare any pizza.

and here it's :

interface Pizza {
    public function prepare(): string;
    public function deliverd(): boolean;
}

class MargheritaPizza implements Pizza {
    public function prepare() {
        return "Preparing Margherita Pizza";
    }
}

class PepperoniPizza implements Pizza {
    public function prepare() {
        return "Preparing Pepperoni Pizza";
    }
}

class PizzaFactory {
    public static function make(string $type): Pizza {
        return match($type) {
            'margherita' => new MargheritaPizza(),
            'pepperoni'  => new PepperoniPizza(),
            default => throw new Exception("Pizza type not found"),
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

and the use case is like(just pass the customer's ordered pizza name there, all things are done in it's own way, ouch):

$pizza = PizzaFactory::make('pepperoni');
echo $pizza->prepare();
echo $pizza->deliverd(); // shanti shanti shanti
Enter fullscreen mode Exit fullscreen mode

No more new ClassName() all over the place. The kitchen (factory) handles it, and it's peace :)

Moral of the story:

The Factory Pattern is like a kitchen in a restaurant — clients (your app) don’t create dishes directly. They ask the kitchen (factory), which prepares and serves the right item.

Comments 0 total

    Add comment