DEV Community

Cover image for Factory Method In Brief: Design Pattern
Harsh Rastogi
Harsh Rastogi

Posted on

Factory Method In Brief: Design Pattern

This pattern is a Creational Design Pattern that provides an interface or abstract for creating the type of object in a superclass but allows the subclass to change the type of object that will be created.

It suggests that developers should replace object creation using
the constructor or using the new operator. This sounds strange but an object will be created using only the constructor that is called inside a factory method.

This may look complex at first glance but believe me, it promotes loose coupling and code reuse.

Let's understand with an Example

Problem Statement

Imagine you want to add different logging behavior for different environments of applications i.e Production, Development, Test, and Debug.

  • In Production: Only loglevel=error|warn is displayed.
  • In Development: All loglevel=info|error|warn|debug is displayed.
  • In Debug: Only loglevel=debug must be displayed.

For simplicity let's only work with two environments i.e Production and Development.

Implementation without using a pattern

// Concrete implementation

class Logger is
    env: string

    public method LogError(message: string): void is
        print message

    public method LogInfo(message: string): void is
        if env = ("Development" or "Test" or "Debug") then
            print message

    public method LogWarning(message: string): void is
        print message

    public method LogDebug(message: string): void is
        if env = ("Development" or "Test" or "Debug") then
            print message
Enter fullscreen mode Exit fullscreen mode
// Implementation of Logger
function DoSomeWork(): void is
    ...
    logger = new Logger()
    ...
    var condition = isValid();

    if condition is true then
        logger.LogInfo("Some work is completed");
        return
    ...
    logger.LogError("Unable to complete work")
Enter fullscreen mode Exit fullscreen mode

Implementation of Logger involves so much of if-else or 'if (the same thing can be performed using the switch).

Imagine in the future

  • Some new environment is added let's say Cloud. So it brings new problems and conditions with it.
    • Making developer change implementation of class Logger.
    • Updating condition according to it
  • Business rules changed for logger
    • So again developer has to change the internal of Logger

Thus, this implementation is not maintainable and prone to unwanted behavior to occur.

Implementing Factory Method

The developer creates an abstract or interface called Logger and provides the concrete implementation for various subclasses of the common superclass Logger for various environments i.e ProductionLogger, DevelopmentLogger, TestingLogger and DebugLogger.

So each method of the subclass of Logger must contain its implementation and business rules.

I know it's hard to grasp to understand because adds up complexity.

UML Diagram For Logger(Superclass) and Concrete Implementation(Subclass). Diagrams show Is-A relation between abstract class and concrete class

For those who don't understand the UML diagram, it shows the IS-A relationship between the abstract Logger class and subclasses (DevelopmentLogger, TestingLogger etc) such that DevelopmentLogger is a Logger.

The developer creates an interface named ILoggerBuilder. That is responsible to provide an object of type Logger according to the requirement or some logic. the UML diagram shows the IS-A relationship between the abstract Logger class and subclasses (DevelopmentLogger, TestingLogger etc) such that DevelopmentLogger is a Logger.

The developer creates an interface named ILoggerFactory. That is responsible to provide an object of type Logger according to the requirement or some logic.

EnvironmentLoggerFactory implements ILoggerFactory that is responsible for creating an appropriate object of Subclass of Logger according to the environment on which the application is executing or say there is complex logic for building some object;

UML diagram for interface ILoggerFactory and Concrete Implementation

Let's write some pseudo-code

abstract class Logger is
    public abstract method LogInfo(message: string): void

    public abstract method LogError(message: string): void

    public abstract method LogDebug(message: string): void

    public abstract method LogWarn(message: string): void
Enter fullscreen mode Exit fullscreen mode
class ProductionLogger inherits Logger is
    public method LogInfo(message: string): void is
      // Does Nothing
      return

    public method LogError(message: string): void is
        print message

    public method LogWarn(message: string): void is
        print message

    public method LogDebug(message: string): void is
        // Does Nothing
        return
Enter fullscreen mode Exit fullscreen mode
class DevelopmentLogger inherits Logger is
    public method LogInfo(message: string): void is
      print message

    public method LogError(message: string): void is
        print message

    public method LogWarn(message: string): void is
        print message

    public method LogDebug(message: string): void is
        return
Enter fullscreen mode Exit fullscreen mode
class TestingLogger inherits Logger is
    public method LogInfo(message: string): void is
      // Does Nothing
      return

    public method LogError(message: string): void is
        print message

    public method LogWarn(message: string): void is
        print message

    public method LogDebug(message: string): void is
        // Does Nothing
        return
Enter fullscreen mode Exit fullscreen mode
class DebugLogger inherits Logger is
public method LogInfo(message: string): void is
// Does Nothing
return

    public method LogError(message: string): void is
        // Does Nothing
        return

    public method LogWarn(message: string): void is
        // Does Nothing
        return

    public method LogDebug(message: string): void is
        print message
Enter fullscreen mode Exit fullscreen mode

Now developer adds EnvironmentLoggerFactory that implements ILoggerFactory

interface ILoggerFactory is
  CreateLogger(): Logger
Enter fullscreen mode Exit fullscreen mode
class EnvironmentLoggerFactory implements ILoggerFactory
  public CreateLogger(): Logger is
    env = getCurrentEnv()

    if env
      is "Production" then return new ProductionLogger()
      is "Development" then return new DevelopmentLogger()
      is "Testing" then return new TestingLogger()
      is "Debug" then return new DebugLogger()

    throw new Exception("No logger attached to current environment")
Enter fullscreen mode Exit fullscreen mode

UML diagram of entire structure

Implementation of Logger

function DoSomeWork(): void is
    ...
    logger = new EnvironmentLoggerFactory().CreateLogger()
    ...
    var condition = isValid();

    if condition is true then
        logger.LogInfo("Some work is completed");
        return
    ...
    logger.LogError("Unable to complete work")
Enter fullscreen mode Exit fullscreen mode

Again imagine the future

  • Some new environment is added let's say Cloud.
    • SOLUTION: Now the developer has to develop a new subclass CloudLogger that inherits Logger.
    • Rules can be implemented without thinking that they will break in the development or production environment.
  • Business rules changed for the logger, for example, all the logs in the cloud must be stored in a database
    • SOLUTION: Just implement a concrete class CloudDatabaseLogger that inherits Logger.

Applicability

  • When developers do not know the exact type of objects that code should work with
    • Factory method separates object creation from the code that uses it
    • It provides an ease to extending the construction of an object
  • When the developer wants to save resources by reusing existing objects rather than by rebuilding them
    • This can be achieved using caching or memoization

Image description

Generic Implementation of Pattern

  1. All the products must be must inherit or implementProduct
  2. Add a factory method inside CreatorFactory that always returns an object of base type Product
  3. Replace all constructor calls in the code with the factory method.

Developer can pass argument inside this factory method to control object creation behavior

Advantages

  1. Avoid tight coupling
  2. Single Responsibility Principal, thus all object creation code is separated, allowing code management easy.
  3. Open/Close Principal, the developer can introduce a new product according to changes without breaking client code.

Conclusion

The factory method is a powerful way to create complex objects it promotes loose coupling, the single responsibility principle, and the open/close principle.

Follow me on GitHub

To know more about this pattern, check this video by Christopher Okhravi

References

Top comments (0)