Implementing Factory Method Design Pattern in PHP

Kartik MehtaKartik Mehta
5 min read

Introduction

Design patterns are essential for developing robust, scalable, and maintainable code. The Factory Method Design Pattern is one of the most commonly used design patterns in object-oriented programming. It belongs to the creational design patterns category and provides a way to delegate the instantiation of objects to subclasses. In this blog, we will explore the Factory Method Design Pattern in PHP, understand its implementation, and create a mini-project to solidify our understanding.

What is the Factory Method Design Pattern?

The Factory Method Design Pattern defines an interface for creating an object but allows subclasses to alter the type of objects that will be created. It promotes loose coupling by reducing the dependency of client classes on concrete classes.

Advantages of Factory Method Design Pattern

  • Encapsulation: Encapsulates object creation logic.

  • Loose Coupling: Reduces dependency between client and concrete classes.

  • Scalability: Easy to introduce new products without changing existing code.

Implementing Factory Method Design Pattern in PHP

Let's dive into the implementation of the Factory Method Design Pattern in PHP.

Step 1: Define a Product Interface

We start by defining an interface for the products that our factory will create.

<?php

interface Product {
    public function getName(): string;
}

Step 2: Create Concrete Products

Next, we create concrete classes that implement the Product interface.

<?php

class ConcreteProductA implements Product {
    public function getName(): string {
        return "Product A";
    }
}

class ConcreteProductB implements Product {
    public function getName(): string {
        return "Product B";
    }
}

Step 3: Define the Creator Abstract Class

The Creator abstract class declares the factory method that returns a Product object. Subclasses will override this method to provide specific implementations.

<?php

abstract class Creator {
    abstract public function factoryMethod(): Product;

    public function someOperation(): string {
        $product = $this->factoryMethod();
        return "Creator: The same creator's code has just worked with " . $product->getName();
    }
}

Step 4: Implement Concrete Creators

Concrete creators override the factory method to create specific products.

<?php

class ConcreteCreatorA extends Creator {
    public function factoryMethod(): Product {
        return new ConcreteProductA();
    }
}

class ConcreteCreatorB extends Creator {
    public function factoryMethod(): Product {
        return new ConcreteProductB();
    }
}

Step 5: Client Code

The client code works with an instance of a concrete creator, albeit through its base interface. As long as the client keeps working with the creator via the base interface, you can pass it any creator's subclass.

<?php

function clientCode(Creator $creator) {
    echo "Client: I'm not aware of the creator's class, but it still works.\n";
    echo $creator->someOperation();
}

echo "App: Launched with the ConcreteCreatorA.\n";
clientCode(new ConcreteCreatorA());
echo "\n\n";

echo "App: Launched with the ConcreteCreatorB.\n";
clientCode(new ConcreteCreatorB());

Detailed Explanation

Let's break down the code snippets and understand each part.

Product Interface

The Product interface defines the methods that all concrete products must implement. In this case, it includes a single method getName().

Concrete Products

Concrete product classes (ConcreteProductA and ConcreteProductB) implement the Product interface. Each class provides its own implementation of the getName() method.

Creator Abstract Class

The Creator abstract class declares the factoryMethod() which must return an object of type Product. It also includes a method someOperation() that demonstrates how the product created by the factory method can be used.

Concrete Creators

Concrete creator classes (ConcreteCreatorA and ConcreteCreatorB) extend the Creator abstract class and override the factoryMethod() to create specific products.

Client Code

The client code uses the Creator interface to work with concrete creators. It calls the someOperation() method, which in turn calls the factoryMethod() to create a product.

Mini Project: Shape Factory

To further solidify our understanding, let's create a mini project using the Factory Method Design Pattern. We will implement a Shape Factory that creates different types of shapes (Circle, Square, Rectangle).

Step 1: Define the Shape Interface

<?php

interface Shape {
    public function draw(): string;
}

Step 2: Create Concrete Shapes

<?php

class Circle implements Shape {
    public function draw(): string {
        return "Drawing a Circle";
    }
}

class Square implements Shape {
    public function draw(): string {
        return "Drawing a Square";
    }
}

class Rectangle implements Shape {
    public function draw(): string {
        return "Drawing a Rectangle";
    }
}

Step 3: Define the Shape Creator Abstract Class

<?php

abstract class ShapeCreator {
    abstract public function factoryMethod(): Shape;

    public function render(): string {
        $shape = $this->factoryMethod();
        return $shape->draw();
    }
}

Step 4: Implement Concrete Shape Creators

<?php

class CircleCreator extends ShapeCreator {
    public function factoryMethod(): Shape {
        return new Circle();
    }
}

class SquareCreator extends ShapeCreator {
    public function factoryMethod(): Shape {
        return new Square();
    }
}

class RectangleCreator extends ShapeCreator {
    public function factoryMethod(): Shape {
        return new Rectangle();
    }
}

Step 5: Client Code

<?php

function clientCode(ShapeCreator $creator) {
    echo $creator->render() . "\n";
}

echo "Client: Let's draw a Circle.\n";
clientCode(new CircleCreator());
echo "\n";

echo "Client: Let's draw a Square.\n";
clientCode(new SquareCreator());
echo "\n";

echo "Client: Let's draw a Rectangle.\n";
clientCode(new RectangleCreator());

Detailed Explanation

Let's break down the mini project code and understand each part.

Shape Interface

The Shape interface defines the methods that all concrete shapes must implement. In this case, it includes a single method draw().

Concrete Shapes

Concrete shape classes (Circle, Square, and Rectangle) implement the Shape interface. Each class provides its own implementation of the draw() method.

Shape Creator Abstract Class

The ShapeCreator abstract class declares the factoryMethod() which must return an object of type Shape. It also includes a method render() that demonstrates how the shape created by the factory method can be used.

Concrete Shape Creators

Concrete shape creator classes (CircleCreator, SquareCreator, and RectangleCreator) extend the ShapeCreator abstract class and override the factoryMethod() to create specific shapes.

Client Code

The client code uses the ShapeCreator interface to work with concrete shape creators. It calls the render() method, which in turn calls the factoryMethod() to create a shape and draw it.

Conclusion

The Factory Method Design Pattern is a powerful tool for creating objects in a flexible and scalable way. By following the principles of this pattern, you can ensure that your code is easy to maintain and extend. In this blog, we have explored the implementation of the Factory Method Design Pattern in PHP, understood each part with detailed code snippets, and created a mini project to solidify our understanding. We hope this comprehensive guide helps you in mastering the Factory Method Design Pattern in your PHP projects.

0
Subscribe to my newsletter

Read articles from Kartik Mehta directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kartik Mehta
Kartik Mehta

A code dependent life form.