Repository Design Pattern in Flutter
In software engineering, design pattern is a reusable solution to a general problem in software design. The repository pattern is one of the most popular design patterns at the moment. If you know Erich Gamma’s book about design pattern, you should know about creational, structural, and behavioral design pattern types, but repository pattern is not listed in any of those. Then what is repository pattern?
Currently, I’m working on a Flutter project. It requires back-end API calls and should also work when it is offline. In this article, I want to share my knowledge about repository pattern and tell you how I implement repository pattern in my Flutter project.
What is repository design pattern?
Repository pattern separates the data access logic and maps it to the business entities in the business logic. Communication between the data access logic and the business logic is done through interfaces.
To put it simply, Repository pattern is a kind of container where data access logic is stored. It hides the details of data access logic from business logic. In other words, we allow business logic to access the data object without having knowledge of underlying data access architecture like connections, commands, cursors, and so on.
A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.
A generic repository should contain a set of methods for performing CRUD operations.
I learned about repository pattern in Google’s Bangkit Academy mobile development learning path. If you really understood repository pattern, then it doesn’t matter what programming language or framework that you use. The repository pattern for Android can easily be converted to be applicable for a Flutter project.
My Implementation
In my Flutter project, I need to be able to get report data even when it’s offline. We use a private back-end and a REST API to fetch the data for a given report.
When I learned about repository pattern from an Android course, this is the diagram of the app architecture that I was supposed follow:
And this is what my app architecture looks like after converted for Flutter framework:
Note: I don’t have to implement something similar to ViewModel in my Flutter app because state management is already built in Flutter’s Stateful Widget.
This design creates a consistent and pleasant user experience whenever they are online or offline. Regardless of whether the user comes back to the app several minutes after they’ve last closed it or several days later, they instantly see the report detail that the app persists locally. If this data is stale, the app’s repository module starts updating the data in the background.
To implement a repository pattern, I first created a repository interface named i_report_repository.dart
. My repository interface defines all of the CRUD operations for Report class.
And then, create an implementation for the repository interface. I named the file report_repository.dart
. the following code contains the implementation for queryAll()
method.
Next, use the repository to get reports. In the code below, I want to get the reports when the widget is rendered. So, I put it in initState()
method.
As you can see from above example using queryAll()
method, the repository class is being used to check the connection. If the device is connected to the internet, it will get new report data from back-end server and store it locally before showing what is stored. Else if the device is not connected to the internet, it will immediately get the stored data inside its local SQLite database. By using repository pattern, I made it more modular, easier to test (link to the test), easier to maintain, which in turn reduce bugs during development.
Thank you for reading. I hope you learn something new about repository pattern.