Daily Dose of Swift

Factory Method Pattern

Photo by Alexa Williams on Unsplash

Factory Method is a creational pattern widely used in development with Swift. It abstracts the instantiation process of an object and controls when and who will create it. The pattern has the class scope and achieves its purpose through inheritance during build time. In Swift, instead of using inheritance, we prefer to use protocol compliance.

The pattern acts on similar objects that have a complex instantiation process and spread over several parts of the code. Factory Method facilitates the process of instantiating an object by encapsulating the creation logic in a factory.

The Pattern defines that similar objects comply with the same protocol so that the client class only knows the abstract type. This process is known as Dependency Inversion, client classes only know one interface of their dependencies.

Use case

The business model of a delivery app is the delivery of food dishes from restaurants. The business team decided to expand the business model to include delivering grocery shopping to users. Software engineers modeled a base interface for the groceries object similar to the restaurant object already in the code base. In this scenario, the use of the Factory Method pattern is a great strategy to encapsulate the creation of these similar objects.

Implementation

//1 - Abstract product
protocol Merchant {
    func presentItens()
}

//2 - Abstract Factory
protocol MerchantFactory {
    func make() -> Merchant
}

//3 - Concrete product
final class Restaurant: Merchant {
    func presentItens() {} 
}

final class Groceries: Merchant {
    func presentItens() {} 
}

//4 - Concrete Factory
struct RestaurantFactory: MerchantFactory {
    func make() -> Merchant {
        return Restaurant()
    }
}
    
struct GroceriesFactory: MerchantFactory {
    func make() -> Merchant {
        return Groceries()
    }
}

//5 - Client
final class Catalog {
    private let merchant: Merchant?

    init(merchantFactory: MerchantFactory) {
        self.merchant = merchantFactory.make()
    }
    
    func present() {
       merchant?.presentItens()
    }
}

let restaurantFactory = RestaurantFactory()
let catalog = Catalog(merchantFactory: restaurantFactory)

catalog.present()

Algorithm:

  • Step 1: Define the interface for products.
  • Step 2: Create the abstract factory with a creation method returning the abstract type of the product.
  • Step 3: Create concrete products conforming to the same interface.
  • Step 4: Create the concrete factory conformed to the defined interface.
  • Step 5: Create the client class and inject a factory type for the object you want to create.

Advantages

  • Encapsulates the creation logic in Factory.
  • Allows a class to depend on an abstract type and not a concrete type.
  • Decreases the coupling between the customer class and the product.
  • Removes the responsibility of creating a product from the client classes.

Conclusion

Factory Method is a widely used pattern to make a code base less coupled and with clear definitions of responsibilities. This pattern is one of the tools that can be used to maintain a flexible and scalable software project.

Thanks for reading!