In a previous post we had the opportunity to define the architecture of our app conceptually. The purpose of this post is to get deep into implementation of key components of this architecture we’re using.
In this post we’ll talk about how we implement:
Repository pattern is a software design pattern that provides an abstraction of data, so that your application can work with a simple abstraction that has an interface. Using this pattern can help achieve loose coupling and can keep domain objects persistence ignorant.
It also makes code more testable as it allow us to inject as a dependency a mock repository that implements that defined interface.
In Tiendeo iOS app, this pattern allow us to abstract the domain layer from the data layer and also, inside data layer, the data repository from its data sources (web API, Realm, User Defaults, etc.).
Let’s see it in a simple scheme:
In domain layer, we define a
RepositoryProtocol that allows us to abstract domain layer (business logic) from data layer following the dependency rule as it is recommended in clean architecture. (+info)
Let’s see it with a common example:
In the example above, the use case in domain layer just has an instance of an object that implements the
FavoriteRepository protocol. This object is injected as a dependency when use case is created (+info). To use case doesn’t care about who implements this protocol, use case is abstracted from data repository.
Now, let’s see how this example continues in data layer:
In data layer,
FavoriteRepository protocol defined in domain layer. It also has different data sources, in this case
localDataSource, which implement the same
FavoritesDataSource protocol. That abstracts
FavoritesDataRepository from data sources implementation.
Each data source internally implements the code required for its source,
remoteDataSource makes an Alamofire request and
localDataSource uses Realm to add favorite entity to local data base.
It also interesting the way
FavoritesDataRepository can manage the different data sources. In this example, using RxSwift, we execute
remoteDataSource method and, in case the result is successfully, we execute
But there are numerous RxSwift operators that can help you in numerous cases. We talk about RxSwift operators in other post if you interested in.
Hope you found this post interesting and useful for your projects. Any question or comment will be welcome!
Thanks and good luck!!!
In the following posts we detail other key components from our architecture: