Greetings, traveler!
In the previous article, we started to learn about Creational design patterns and discussed the Factory Method. This time, we will look at the Abstract Factory pattern.
An Abstract Factory can be helpful in situations where we want to hide the internal details of an object creation behind a public API. This pattern can also be beneficial when creating an object is a complex process that needs to be repeated many times throughout an application.
Unlike Java, C++, and C#, Swift doesn’t have an abstract class. But fear not — we can harness the power of Swift Protocols to implement a similar design pattern effectively.
The Abstract Factory design pattern has five main components:
- Abstract product
- Concrete product
- Abstract factory
- Concrete factory
- Client
Example of usage
Let’s bring the Abstract Factory pattern to life with a relatable example.
Imagine you’re preparing a full dinner — a main dish, a dessert, and a drink.
Each cuisine (Italian, Japanese, etc.) provides its own set of dishes that work well together.
That’s exactly what the Abstract Factory pattern represents: creating consistent families of related products.
Abstract Products
We start by defining our abstract product protocols:
protocol MainDishProtocol {
func cook()
}
protocol DessertProtocol {
func serve()
}
protocol DrinkProtocol {
func pour()
}Concrete Products
Each product family will have its own concrete implementations:
struct Pasta: MainDishProtocol {
func cook() { print("🍝 Cooking pasta") }
}
struct Tiramisu: DessertProtocol {
func serve() { print("🍰 Serving tiramisu") }
}
struct Wine: DrinkProtocol {
func pour() { print("🍷 Pouring wine") }
}
struct Sushi: MainDishProtocol {
func cook() { print("🍣 Cooking sushi") }
}
struct Mochi: DessertProtocol {
func serve() { print("🍡 Serving mochi") }
}
struct Sake: DrinkProtocol {
func pour() { print("🍶 Pouring sake") }
}
Abstract Factory
Now we define the interface for creating a whole family of products:
protocol DinnerFactoryProtocol {
func makeMainDish() -> MainDishProtocol
func makeDessert() -> DessertProtocol
func makeDrink() -> DrinkProtocol
}Concrete Factories
Each concrete factory will produce a consistent set of related products:
struct ItalianDinnerFactory: DinnerFactoryProtocol {
func makeMainDish() -> MainDishProtocol { Pasta() }
func makeDessert() -> DessertProtocol { Tiramisu() }
func makeDrink() -> DrinkProtocol { Wine() }
}
struct JapaneseDinnerFactory: DinnerFactoryProtocol {
func makeMainDish() -> MainDishProtocol { Sushi() }
func makeDessert() -> DessertProtocol { Mochi() }
func makeDrink() -> DrinkProtocol { Sake() }
}Client
Finally, the client depends only on the abstract factory, not on any specific types:
final class DinnerClient {
private let factory: DinnerFactoryProtocol
init(factory: DinnerFactoryProtocol) {
self.factory = factory
}
func serveDinner() {
let main = factory.makeMainDish()
let dessert = factory.makeDessert()
let drink = factory.makeDrink()
main.cook()
dessert.serve()
drink.pour()
}
}Usage
let italianDinner = DinnerClient(factory: ItalianDinnerFactory())
italianDinner.serveDinner()
let japaneseDinner = DinnerClient(factory: JapaneseDinnerFactory())
japaneseDinner.serveDinner()Conclusion
The job is done, and I hope you have enjoyed this article. The following article will discuss how and when to use the Builder Pattern. See you soon!
Check out other posts in the Design Patterns series:
- Visitor Design Pattern in Swift
- Themplate Method Design Pattern in Swift
- Strategy Design Pattern in Swift
- State Design Pattern in Swift
- Observer Design Pattern in Swift
- Memento Design Pattern in Swift
- Mediator Design Pattern in Swift
- Iterator Design Pattern in Swift
- Command Design Pattern in Swift
- Chain of Responsibility Design Pattern in Swift
- Proxy Design Pattern in Swift
- FlyWeight Design Pattern in Swift
- Facade Design Pattern in Swift
- Decorator Design Pattern in Swift
- Composite Design Pattern in Swift
- Bridge Design Pattern in Swift
- Adapter Design Pattern in Swift
- Singleton Design Pattern in Swift
- Prototype Design Pattern in Swift
- Builder Design Pattern in Swift
- Factory Method Design Pattern in Swift
- Design Patterns: Basics
