In the beginning of this year, I was looking at different ways to achieve dependency injection in Swift. A colleague of mine mentioned this concept of the Cake Pattern.
I did some research, trying to find out what this was all about and how I could use it within The Swift code base. I found that it was a concept that originates from Scala, which is based on the concept that “one should only inject via an interface (protocol), not concrete class”.
So, if this is a Scala pattern, how do we achieve this in Swift? We do so with Protocol Extensions.
Lets get to the CODE
We will start by creating a struct which will be our model. This will hold our data that we will be receiving.
struct Product {
var name: String
var price : Double
}
We then create a protocol that will define our repository. This protocol will have a method that will fetch all of our products for us.
protocol ProductsRepository {
func fetchProducts() -> [Product]
}
Now we will need some kind of implementation for our repository. We will create a ProductRepositoryImplementation struct, that will conform to our ProductRepository protocol. In this implementation we will just return some dummy products.
struct ProductsRepositoryImplementation : ProductsRepository {
func fetchProducts() -> [Product] {
return [Product(name: "Adidas Sneakers", price: 2030.0), Product(name: "Nike Sneakers", price: 1000.0)]
}
}
This is where the magic happens
Lets create another protocol and name it ProductsRepositoryInjectable. On this protocol, lets add a property of type ProductsRepository and make this a read only property. We will now create a protocol extension, that will provide us with a default implementation for this property. This being the ProductRepositoryImplementation we created earlier.
protocol ProductsRepositoryInjectable {
var products : ProductsRepository {get}
}
extension ProductsRepositoryInjectable {
var products : ProductsRepository {
return ProductsRepositoryImplementation()
}
}
At this point, we have just achieved dependency injection and we have not used any third party libraries. Just pure Swift. What makes this so powerful, is that we can now swop out the implementation at anytime and where we are injecting this protocol will not need to change.
So, how would we use this might be the next question? Well lets create a viewmodel where we can inject the ProductsRepositoryInjectable. Within the init, we will use our injected property and loop through each product and printing the name and cost.
struct ProductViewModel: ProductsRepositoryInjectable {
init() {
self.products.fetchProducts().forEach {
print("This \($0.name) costs R\($0.price)")
}
}
}
ProductViewModel()
/*
This Addidas Sneakers costs R2030.0
This Nike Sneakers costs R1000.0
*/
There you go. Dependency Injection with the awesome Cake Pattern.
Why is this useful? It makes your code more loosely coupled, testable and reusable. These are all concepts we want when writing clean code.
Go try it and let me know what you think. If you have any questions, please leave them in the comments below.
Get in Touch!
This Blog was originally published on Medium: https://medium.com/swift-programming/dependency-injection-with-the-cake-pattern-3cf87f9e97af