Factory Method – Design Patterns in Swift

Introduction

Factory Method defines an interface for creating an object, but lets subclasses decide which class to instantiate. In class-based programming, this pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.

Factory Method – UML

Use Factory Method in Swift

The Creator protocol declares the factory method which returns a new object of a Product class. And the Creator’s subclasses usually provide the implementation of this method. The Creator’s primary responsibility is not creating products. Usually, it contains some core business logic that relies on Product objects. Subclasses can indirectly change that business logic by overriding the factory method and returning a different type of product from it.

import XCTest

protocol Creator {

    func factoryMethod() -> Product

    func someOperation() -> String
}

Next, we extend the Creator protocol to implements the default behavior of the Creator.

extension Creator {

    func someOperation() -> String {

        let product = factoryMethod()
        return "Creator: The same creator's code has just worked with " + product.operation()
    }
}

Then, we create concrete Creators who change the resulting product’s type. Note that the signature of the method still uses the abstract product type, even though the concrete product is actually returned from the method. This way the Creator can stay independent of concrete product classes.

class ConcreteCreator1: Creator {

    public func factoryMethod() -> Product {
        return ConcreteProduct1()
    }
}

class ConcreteCreator2: Creator {

    public func factoryMethod() -> Product {
        return ConcreteProduct2()
    }
}

Next, we declare the Product protocol which declares the operations that all concrete products must
implement and we declare concrete Creators provide various implementations of the Product protocol.

protocol Product {

    func operation() -> String
}

class ConcreteProduct1: Product {

    func operation() -> String {
        return "{Result of the ConcreteProduct1}"
    }
}

class ConcreteProduct2: Product {

    func operation() -> String {
        return "{Result of the ConcreteProduct2}"
    }
}

After that, we declare a class working with an instance of a concrete Creator, albeit through its base protocol.

class Client {
    
    static func someClientCode(creator: Creator) {
        print("Client: I'm not aware of the creator's class, but it still works.\n"
            + creator.someOperation())
    }
}

Let’s see how it all works together.

class FactoryMethodConceptual: XCTestCase {

    func testFactoryMethodConceptual() {

        print("App: Launched with the ConcreteCreator1.")
        Client.someClientCode(creator: ConcreteCreator1())

        print("\nApp: Launched with the ConcreteCreator2.")
        Client.someClientCode(creator: ConcreteCreator2())
    }
}

As you have seen, the Application picks a creator’s type depending on the configuration or environment.

Conclusion

In summary, the Factory Method design pattern defines a method, which should be used for creating objects instead of a direct constructor call (new operator). Subclasses can override this method to change the class of objects. Open and optimize your code right now!

2 comments

Leave a Reply

Your email address will not be published. Required fields are marked *