Home Simplify Factory Method (Creational Pattern)
Post
Cancel

Simplify Factory Method (Creational Pattern)

πŸŒ‘ Why Factory Pattern

Six months back, Coder Spidey needed to develop SignIn functionality for her movie review application. She needed to integrate the Google authentication mechanism. She knew that iOS apps must include Apple sign-in if they offer other authentication methods. She anticipated Facebook and other SignIn methods would be available in the future.

She was interested in a common interface for all authentication mechanisms. Also, every authentication mechanism has an object that needs to be created and set up before use. She wants the creation logic to be separate from the login screen. She visualises a factory of authentication methods which generates an authentication mechanism if you ask.

πŸŒ₯️ Outline

The Factory method pattern is a creational design pattern that provides an interface for creating objects of a similar type. The pattern defines the requirement to have a method responsible for creating objects. objects created by the method adhere to a common interface.

Factory Method Pattern - A pattern defines an interface with a method to create objects.

🌜Factory In Real World

The word β€œFactory” creates a picture of a building with chimneys. Further, the mind will think about where some goods are manufactured.

In programming, a factory pattern is used to create objects, similar to how a factory in the real world produces goods.

πŸŒ• Solution

Based on the Factory Method pattern Coder Spidey creates an interface AuthenticationFactory with factory method createAuthManager. The method will return an object that conforms to the AuthManager interface.

Further, Spidey developed an individual authentication factory (concrete class) for various authentication mechanisms. The component GoogleAuthenticationFactory is responsible for constructing the objects required in the Google Authentication mechanism i.e. GoogleAuthManager.

Similarly, a separate component for the Apple Authentication mechanism.

You might wonder why separate classes are needed for object creation. The advantage we are getting here is the objects produced by a factory adhere to a standardised interface, so clients using the factory do not bother about the object type. Code is loosely coupled because no specific code is required at the client end based on object type.

So, in the above case, the Login screen does not require any extra handling, whether it is handling Google or Apple Authenticator.

Also, another advantage is easy to incorporate new object types in future with minimal impact.

Factory Method Componentes

Creator:
An interface or abstract class that declares the factory method. The method is responsible for creating objects. AuthenticationFactory is a creator.
Concrete Creator:
A class that confirms the creator. Each concrete class is responsible for creating an object. GoogleAuthenticationFactory is a concrete creator.
Product:
The product in a factory defines an interface for all objects that the factory method can create. AuthManager is a product.
Concrete Product:
A class that adheres to the Product and represents an actual object return by the factory method. GoogleAuthManager is a concrete product.

🌟 Where To Apply

Β  Β  Use the Factory method to support multiple options for the single behaviour.
Sometimes, you need to support multiple types of objects for a single behaviour. When on run-time user selects an option particular type of object should be consumed. like choosing payment gateways(Paypal, Amazon Pay, Payu, etc).
You can create a payment factory in an application to support various payment methods. Based on user selection the application can use the specific factory to get the object for the payment.

Β  Β  Use the Factory method to provide an extension in your library.
Suppose you are implementing a payment library for a mobile application. You provided support for PayPal and Amazon Pay in the library. Now Spidey want to use your library in the movie review application to book movie tickets in the application. The only thing preventing Spidey from using the library is not allowing support for the Paytm payment gateway.
You can help her by designing a payment factory with an interface or abstract class called PaymentService. Spidey can create PaytmService confirms to PaymentService. In this way, any other payment service can be used without interrupting the flow of BookMyTicket.

In the above flow, the flow for booking movie tickets will be intact as PaytmService has some interface that AmazonPayServie or PaypalService. Spidey can happily use the library developed by you and add custom service also.

πŸŒ“ To Gain Something, You Have To Lose

Design patterns are solutions to common problems in software design. They offer a structured approach to solving problems, like a blueprint. It is not that the problem cannot be solved without a design pattern, however, a solution using a design pattern will provide better flexibility, scalability and n number of benefits. However, every benefit comes with a trade-off. Let’s explore what that means in the context of the Factory Method pattern.

Loose Coupling vs Overhead

In the factory method, the Client BookMyTicket is decoupled from the concrete classes which create objects. The client is unaware of the implementation details of object creation and only knows an abstract method to create an object. Further, the client loosely depends upon the product through an Interface PaymentService, so extending the system without impacting client code is easier.

But it is an overhead to create an object you need a separate concrete factory class. It requires a generic boilerplate code every time a new product has been added to the system.

Scalability vs Complexity

As Spidey added a new service PaytmService without impacting the flow of BookMyTicket, you can extend the factory to support new products. It adheres to the open/closed principle as you are not impacting the existing flow while adding a new product.

However, it becomes complex as more classes will be added to the system while introducing a new product. Also as the client is dependent upon the interface only as the system grows it becomes hard to debug.

🌚 Some Interesting Facts

Β  Β  Abstract Factory & Factory Method
Abstract Factory pattern uses composition to delegate the responsibility of creating an object to another class while the Factory Method design pattern uses inheritance and relies on a subclass to create an object.

Β  Β  Simple Factory & Factory Method
There is one common variant of Factory family Simple Factory to use Factory in any application. It is a class or function that creates an object. There is no blueprint for the Simple Factory. You can define a structure or class with a function that generates objects depending on specific criteria.

With Simple Factory, BookMyTicket needs to call a method of the PaymentFactory class and it returns the required object. You can use this variant if the type of object is simple. However, Simple Factory is not a design pattern just a programming style.

Simple Factory Code Snippet:

1
2
3
4
5
6
7
8
9
10
11
class PaymentFactory {
    public func createPaymentService(type: String) {
        if type == "paypal" {
            return Paypal()
        } else if type == "Amazon pay" {
            
        } else if type == "paytm" {
            
        }
    }
}

Code Example (Swift)

Product Interface:

1
2
3
protocol PaymentService {
    func startPayment()
}

Creator Interface:

1
2
3
protocol PaymentFactory {
    func createPaymentService() -> PaymentService
}

Concrete Product 1:

1
2
3
4
5
6
struct PaypalPaymentService: PaymentService {
    // initialize PayPal service SDK
    func startPayment() {
        // payment using PayPal SDK.
    }
}

Concrete Product 2:

1
2
3
4
5
6
struct AmazonPayPaymentService: PaymentService {
    // initialize AmazonPay  SDK
    func startPayment() {
        // payment using AmazonPay SDK.
    }
}

Concrete Creator 1:

1
2
3
4
5
struct PaypalPaymentFactory: PaymentFactory {
    func createPaymentService() -> PaymentService {
        return PaypalPaymentService()
    }
}

Concrete Creator 2:

1
2
3
4
5
struct AmazonPayPaymentFactory: PaymentFactory {
    func createPaymentService() -> PaymentService {
        return AmazonPayPaymentService()
    }
}
This post is licensed under CC BY 4.0 by the author.

Swift Dynamic Member Lookup

-

Comments powered by Disqus.