Factory design pattern and its variations in PHP

One of the most used and most useful of all design patterns in software development is the factory design pattern. The factory belongs to the creational group of design patterns, so we can assume that we can use this pattern when our implementation classes are to complicated to be built in concrete use cases and we need a solution when a particular class would be in charge to create this builds. That’s where factory classes are coming in help. Let’s see this in practice.

The factory pattern can be found and used in multiple slightly different variations, like:

  • Simple factory
  • Factory method
  • Abstract factory

Simple factory pattern

This is the most straight forward variation which can be used in different cases with regarding the fact that we will have only one implementation of the factory without additional sub-classes and abstractions. Let’s say that we have a module which is in charge to handle users on our platform. We will have different types of users on the platform and we need different classes for creating users which relates them to all different kinds of permissions available. Let’s see how this user classes will look like.

class Student
{
    protected $studentUser;
    protected $studentPermissions;
    protected $userService;

    public function __construct(StudentUserService $studentUser, StudentPermissions $studentPermissions, StudentService $userService)
    {
        $this->studentUser = $studentUser;
        $this->studentPermissions = $studentPermissions;
        $this->userService = $userService;
    }

    public function create(array $userData)
    {
        // Create student user implementation
    }
}
class Professor
{
    protected $professorUser;
    protected $professorPermissions;
    protected $userService;

    public function __construct(ProfessorUserService $professorUser, ProfessorPermissions $professorPermissions, ProfessorService $userService)
    {
        $this->professorUser = $professorUser;
        $this->professorPermissions = $professorPermissions;
        $this->userService = $userService;
    }

    public function create(array $userData)
    {
        // Create professor user implementation
    }
}

As we can see from the classes above, it is very common for classes that operate with a complicated functionality to have multiple dependencies in their constructors. So we can conclude that every time we will use this classes, we will need to deliver this dependencies and to write them over and over again. If we are developing an application where, for example, we are creating users through a registration form and also we have an admin panel that has the same functionality, we can agree with the fact that we will need to do this at least two times right? If we use the simple factory pattern here, we will have an additional layer which will be in charge for creating this complicated objects and dependencies and it will look something like this:

class UserFactory
{
    public function buildStudent(): Student
    {
        return new Student(new StudentUserService(), new StudentPermissions(), new UserService());
    }

    public function buildProfessor(): Professor
    {
        return new Professor(new ProfessorUserService(), new ProfessorPermissions(), new UserService());
    }
}

Now the actual usage of this implementations is much simpler and using it in multiple places will be less painful to manage and the maintenance process will be smoother.

$user = new UserFactory();
$student = $user->buildStudent();
$student->create($userData);

$user = new UserFactory();
$professor = $user->buildProfessor();
$professor->create($userData);

The simple factory pattern could be implemented in a more dynamic way with sending the name of the implementation class as a parameter which will reduce the code of the factory class, but please be aware of the SOLID principles when doing this and in which way this could be beneficial.

class UserFactory
{
    public function build(string $type)
    {
        return new $type();
    }
}
$user = new UserFactory();
$student = $user->build('Student');
$student->create($userData);

Factory method pattern

This variation of the factory pattern basically has the same purpose and usage, to create objects of classes and implementations of similar nature. The main difference in the factory method is that the pattern is represented usually through an abstract class which is contained by an abstract method that will initialize the different method classes and an additional method which will be used in the separate class methods usage. Sounds confusing right? Let’s represent this as a real code example, it will be much more understandable.

abstract class UserFactory
{
    protected abstract function createUser();

    public function build()
    {
        return $this->createUser();
    }
}

class StudentFactoryMethod extends UserFactory
{
    protected function createUser(): Student
    {
        return new Student(new StudentUserService(), new StudentPermissions(), new UserService());
    }
}

$user = new StudentFactoryMethod();
$student = $user->build();
$student->create($userData);

If we need to implement a factory method for creating professor users, the only thing we’ll need to do is to create another ProfessorFactoryMethod class that will handle the user creation of type “professor”.

Abstract factory pattern

The abstract factory variation is characterized by implementing the factory classes by a common interface. That means we have different class implementations for every different user type which will implement one single interface. This variation can be used in cases when we want or need to use those implementations in a client class with dependency injection which will additionally make the code more maintainable and loosely coupled. Let’s see how this will look like presented with code.

interface UserInterface
{
    public function build();
}

class StudentFactory implements UserInterface
{
    public function build(): Student
    {
        return new Student(new StudentUserService(), new StudentPermissions(), new UserService());
    }
}

class ProfessorFactory implements UserInterface
{
    public function build(): Professor
    {
        return new Professor(new ProfessorUserService(), new ProfessorPermissions(), new ProfessorService());
    }
}

class UserClient
{
    protected $user;

    public function __construct(UserInterface $user)
    {
        $this->user = $user;
    }

    public function create($userData)
    {
        $user = $this->user->build();
        return $user->create($userData);
    }
}

$user = new UserClient(new StudentFactory());
$user->create($userData);

Conclusion

As you can see from all of the above examples, all variations of the factory pattern has the same purpose at the end, only the implementations are slightly different and could be used in different cases accordingly. Some colleagues would like to say that these are different patterns and that’s not wrong at all. But we can assume that the factory pattern could be seen as one with different variations since the purpose of the pattern at the end is the same, creating and management of objects of similar nature.

I would say that design patterns are the poetry of the programming world 🙂 and probably that’s not far from the true regarding how much interest and passion they cause to developers. But my experience and the experience of many other developers out there says that we are leaving and working in an imperfect world, so my suggestion will be, do not try to use particular patterns in your code no matter what. Sometimes their excessive and inappropriate use could abstract your code a lot, that in concrete cases could complicate your future maintenance.