Hallo koningen en koninginnen, Leo hier. The topic today is how to create a Generic Factory Pattern in Swift.
We’ll explore a very special Factory pattern in Swift. The factory method is a very interesting one because is a creational pattern. The creational design patterns provide various object creation mechanisms such as initializers or functions, which increase flexibility and reuse of existing code.
Builders, Factories, Prototypes, and Singletons are all creational patterns.
Each creational pattern solves a specific pain/problem, in the factory pattern we use the factory to produce a product that we want to use. This way we can move the configuration logic from one class to the factory itself. In other words, if you want to hide the complexity of creating an object in your project the Factory is here to help you!
One good thing to say about design patterns is: Design Patterns are like clothes, use the appropriate clothes for the weather. You can wear a lot of layers of clothes but not necessarily, in case of hot weather, it will be the best outfit for you.
A final disclosure: I will not explain what is a factory and all the theory crafting behind it nor will follow “by the book” the abstract factory pattern, although the factory is explained here is a very simple kind of factory. No more talking, let’s code! But first…
Painting of The Day
The painting is Mille Miglia Bentley 6.5 Litre 1926 from Paul Smith. Born in 1948 and grew up in the center of London and bought his first tubes of oil paint when he was about 15 years old in their local art shop in Hampstead.
He has been interested in classic cars and classic motorsport since his first visit to Brighton Speed trials in 1968, it’s remarkable that the cars he was fascinated with then are still around today. He still paints landscape and London street scenes, but his main interest is in the classic car scene.
I choose this painting because the example of Factory remembers me of cars, and the code examples below are all about making Car Factories.
The Problem – Generic Factory Pattern in Swift
Imagine that you are writing a class A and you need to use the class B. But class B takes several steps to be initialized, but you don’t want that class A to know how to configure class B.
First of all, let’s create a class Ferrari
:
struct Ferrari { let engine: String var timestamp: Date? init(year: String, nickname: String, driver: String, engine: String) { self.engine = engine } func drive() { print("The car type is \(engine)") } }
As you see the Ferrari class has a lot to configure. The year, the nickname of the car, the driver, and the engine. And also even after we have created the Ferrari object we still need to configure the timestamp of it. In your codebase, this could be an object that needs a lot of other objects/steps to be initialized. Like a manager that needs other services or initializations to work.
So if I want a CarSeller
to drive the Ferrari
I could do something like this:
class CarSeller { func showCars() { let ferrari = Ferrari(year: "get from the yearCatalog Service", nickname: "Search in user defaults the nickname of the car", driver: "Get the first from a Core Data table", engine: "3.5") ferrari.timestamp = Date() ferrari.drive() } } let carSeller = CarSeller() carSeller.showCars()
This works but you see that now CarSeller
has to know how to initialize and configure the Ferrari
class?
Encapsulate the Object Creation
So to simplify this CarSeller class we will create a generic factory to handle every possible object that we want to create, let’s start with the protocol:
protocol GenericFactory { associatedtype Input associatedtype Output func build(config: Input) -> Output }
This protocol says: Hey every generic factory should have an Input Type, an Output Type, and a function that receives the Input Type and return the Output Type. Observe that Input and Output types can be everything and we can do great tricks with them.
Now we should implement the Factory itself. The factory will take a generic factory and the configuration to return the product of any possible factory.
struct Factory { static func create<Output, Input, Factory: GenericFactory>(_ object: Factory,_ configuration: Input) -> Output where Factory.Output == Output, Factory.Input == Input { object.build(config: configuration) } }
There’s a lot going on here so let’s break it down:
- First, you have the generic parameters inside angle brackets: Output, Input, and a Factory that conforms to the
GenericFactory
protocol. - You have the function parameters: the factory object will be any object that conforms to
GenericFactory
, and the configuration is anything that theGenericFactory
considers being the necessary configuration. - The return type of the factory static function is Output. We have to tie this to the output of the Factory in the
where Factory.Output == Output
. We also are tying together theconfiguration
input from the function parameters to the Factory(GenericFactory) Input type, you see this in the where clause `Factory.Input == Input`. - Now we just need to call the
object.build(config:configuration)
and it’s done! (We can omit thereturn
in this case because the function body has one line and the return type of that line matches with the return type of the enclosing function)
We are all set to start fabricating our fabrics! Let’s start with the FerrariFactory
:
struct FerrariFactory: GenericFactory { func build(config: String) -> Ferrari { var ferrari = Ferrari(year: "getFrom Year service", nickname: "get from other data structure", driver: "Find the first avaliable in Core Data", engine: config) // imagine very big configuration with a lot of steps here ferrari.timestamp = Date() return ferrari } }
And you can now create your Ferraris inside your CarSeller
a class like this:
class CarSeller { func showCars() { var ferrari = Factory.create(FerrariFactory(), "3.5") ferrari.drive() } }
Very cool isn’t it?
Using Swift types to leverage the solution
I have two more things to show that you might be thinking: A product with more than one parameter and a product with zero parameters.
For the zero parameter case you case use the Optional Never
type like this, for example:
struct FordFactory: GenericFactory { func build(config: Never?) -> Ford { // very big configuration here return Ford(year: "getFrom Year service", nickname: "get from other structure", driver: "Find the first avaliable in Core Data", engine: "") } } let newFord = Factory.create(FordFactory(), nil)
And if you want more than one parameter we can use a simple Tuple
:
struct FordFactory: GenericFactory { func build(config: (engine: String, year: String)) -> Ford { // very big configuration here return Ford(year: config.year, nickname: "get from other structure", driver: "Find the first avaliable in Core Data", engine: config.engine) } } let newFord = Factory.create(FordFactory(), (engine: "2.4",year: "1993"))
That’s all!
Continue Studying
If you liked a generic way to create a factory in Swift you will also love how to implement the memento design pattern in Swift. That is something really interesting if you have to undo the actions of your users and you don’t want to break your object state encapsulation.
Dependency injection is a good pattern to use in your apps and how about to learn with the legendary Uber developers how you could do that? Read in this article how to create a dependency injection using Needle framework.
Summary – Generic Factory Pattern in Swift
Today we see a very good pattern to extract the configuration and creation of your objects. This can simplify your stack and upgrade the readability of your functions and classes. Use design patterns when necessary and to solve specific problems.
That’s all my people, I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or leave a comment saying hello. You can also sponsor posts and I’m open to freelance writing!
You can reach me on LinkedIn or Twitter and send me an e-mail through the contact page.
Thanks for reading and… That’s all folks.
Credits: