Discover Design Pattern: Factory Design Pattern
6 mins read

Discover Design Pattern: Factory Design Pattern

Within the profession of software engineering, design patterns are essential resources that help architects as well as developers effectively address common issues. The Factory Design Pattern is one such pattern that is essential to creating of objects. This article explores the Factory Design Pattern, covering its issues, solutions, benefits, drawbacks, and practical uses.

What is the Factory Design Pattern?

The Factory Design Pattern falls under the creational design patterns category. The Factory Method creational design pattern provides an interface for producing objects in a superclass, allowing subclasses to change the type of objects that are created. It essentially encapsulates the logic for creating objects, encouraging loose coupling and improving flexibility.

Problems with Direct Object Instantiation

It’s important to understand the problems that the Factory Design Pattern aims to solve before diving into it. There can be a number of issues with direct object instantiation, which creates objects across the codebase using the new keyword:

  1. High Coupling: Changes to implementations are difficult to make without changing client code because direct instantiation binds client code to concrete classes.
  2. Complexity: It is difficult to alter implementations without changing client code when direct instantiation links client code to concrete classes.
  3. Lack of Abstraction: It might be challenging to handle object generation variations when using direct instantiation since it frequently lacks abstraction.

Solution: Implementing the Factory Design Pattern

By adding an independent factory class that is in charge of creating objects, the Factory Design Pattern addresses these problems. Encapsulating the object generation process, this class encourages high cohesion and low coupling. Important elements of the Factory Design Pattern consist of:

  1. Factory Interface/Abstract Class: Defines a common interface for all factory classes, ensuring consistent object creation.
  2. Concrete Factories: Subclasses implementing the factory interface to create specific types of objects.
  3. Client Code: Utilizes factory methods to request objects without concerning themselves with the creation logic.

Pros of the Factory Design Pattern

  1. Flexibility: Allows easy switching between object implementations without modifying client code.
  2. Scalability: Simplifies the addition of new object types by extending factory classes.
  3. Encapsulation: Encapsulates object creation logic, promoting cleaner and more maintainable code.
  4. Enhanced Testing: Facilitates unit testing by enabling the substitution of mock objects via dependency injection.
  5. Abstraction: Promotes abstraction by decoupling client code from concrete implementations.

Cons of the Factory Design Pattern

  1. Complexity: Introducing multiple factory classes can increase code complexity, especially in smaller projects.
  2. Overhead: The additional layer of abstraction may introduce overhead, impacting performance in performance-sensitive applications.
  3. Learning Curve: Developers unfamiliar with design patterns may find it challenging to grasp initially.

Real-World Example: Database Connection Factory

Let’s consider a real-world example to illustrate the application of the Factory Design Pattern. A database connection factory. Assume a web application requiring connections to different types of databases such as MySQL, PostgreSQL, and SQLite.

Discover Design Pattern: Factory Design Pattern - TechnologiesPost

Below is represent the code that will create interface of DatabaseConnectionFactory that factory will implements to MySqlConnectionFactory and PostgreSqlConnectionFactory.

interface DatabaseConnectionFactory {
    public function createConnection(): DatabaseConnectionFactory;
}

class MySqlConnectionFactory implements DatabaseConnectionFactory {
    public function createConnection(): DatabaseConnectionFactory {
        return new MySqlConnectionFactory();
    }

    public function myConnection(){
        echo "This is MySqlConnectionFactory";
    }
}

class PostgreSqlConnectionFactory implements DatabaseConnectionFactory {
    public function createConnection(): DatabaseConnectionFactory {
        return new PostgreSqlConnectionFactory();
    }

    public function myConnection(){
        echo "This is PostgreSqlConnectionFactory";
    }
}

// Client Code
$conn = "MySql";
if($conn == "MySql") {
    $factory = new MySqlConnectionFactory();
    $connection = $factory->createConnection();
    $connection->myConnection();
} else {
    $factory = new PostgreSqlConnectionFactory();
    $connection = $factory->createConnection();
    $connection->myConnection();
}

In this example, the DatabaseConnectionFactory interface defines a common method for creating database connections. Concrete factory classes like MySqlConnectionFactory and PostgreSqlConnectionFactory implement this interface to create MySQL and PostgreSQL connections, respectively. Client code can then request database connections without concerning itself with the underlying implementation.

Hospital Management System Example: Factory Method pattern

In a hospital management system, the Factory Method pattern can be used to address various challenges related to the creation of medical staff objects, such as doctors, nurses, and administrative personnel. Let’s explore some of the common problems encountered in such a system and how the Factory Method pattern can help mitigate them:

Problems in Hospital Management System

A hospital’s need to dynamically produce instances of various medical staff types based on departmental needs, specializations, and shift requirements is common. There may be tight coupling and code duplication if these objects are directly instantiated throughout the program.

Solution: Applying Factory Method Pattern

A solution is offered by the Factory Method pattern, which encapsulates the object creation procedure inside of specific factory classes. By assigning a specific type of medical staff object to each factory class, loose coupling is encouraged and code maintainability is improved.

Factory Design Pattern with pros, Cons and realtime example

Implementation Example

Let’s consider an example implementation of the Factory Method pattern in a hospital management system:

// Abstract class representing a medical staff member
abstract class MedicalStaff {
    protected $name;
    protected $department;
    
    // Constructor with common initialization logic
    public function __construct($name, $department) {
        $this->name = $name;
        $this->department = $department;
    }
    
    // Abstract method to be implemented by concrete classes
    abstract public function work();
}

// Concrete class representing a doctor
class Doctor extends MedicalStaff {
    public function work() {
        echo "{$this->name} is examining patients in the {$this->department} department.\n";
    }
}

// Concrete class representing a nurse
class Nurse extends MedicalStaff {
    public function work() {
        echo "{$this->name} is providing care to patients in the {$this->department} department.\n";
    }
}

// Abstract factory class for creating medical staff objects
abstract class MedicalStaffFactory {
    abstract public function createStaff($name);
}

// Concrete factory class for creating doctors
class DoctorFactory extends MedicalStaffFactory {
    public function createStaff($name) {
        return new Doctor($name, "General Medicine");
    }
}

// Concrete factory class for creating nurses
class NurseFactory extends MedicalStaffFactory {
    public function createStaff($name) {
        return new Nurse($name, "Emergency Care");
    }
}

// Client code
$doctorFactory = new DoctorFactory();
$doctor = $doctorFactory->createStaff("Dr. Smith");
$doctor->work();

$nurseFactory = new NurseFactory();
$nurse = $nurseFactory->createStaff("Nurse Johnson");
$nurse->work();

Conclusion

By addressing typical issues with direct instantiation, PHP’s Factory Design Pattern offers a reliable method for handling object generation logic. It encourages flexibility, scalability, and maintainability in software projects by encapsulating object creation. Applying its ideas wisely can greatly improve the quality of the code and design flexibility.

Share your Love