Repository Design Pattern

While developing Android applications in most of them you need to persist data in some kind of storage. In most cases this storage will be SQLite. Probably you want to access data in readable and easy way. What do you do then? Yes… you look for nice looking ORM. You can start to create classes for tables and design all possible method you’re likely to use:

Does it look familiar? Is it wrong? Well, no, but can be better.

Instead of god class (or couple of them) you can follow Single Responsibility Rule and use Repository Design Pattern instead. Following the definition ( http://martinfowler.com/eaaCatalog/repository.html):

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes

Let’s start with base definition of Repository:

As you can see I replaced Criteria with Specification. Basically it’s the same, but Specification seems to be more independent from where you’re going to store the data. While using it, I found it extremely useful to add two additional methods:

It’s really what you need. In almost all applications you need to store more than one item and remove a couple of them. RDP should make your live easier, shouldn’t it?

There is also Specification interface which is only regular marker interface. Once we’ve defined what the repository is, we can start to use Specifications:

public interface SqlSpecification extends Specification {
String toSqlQuery();
}

Basic implementation of Repository for SQLite can be for instance:

This can be a way simpler by using lambdas or Kotlin ❤. For this example I’ve deliberately added only implementation of add and query methods because other methods will look very similar. It’s more than sure, you’ve noticed Mapper interface. Its responsibility is to map one object to another. In this case I found it really useful. While using RDP, mapper classes help to keep you focused on what’s important.

public interface Mapper<From, To> {
To map(From from);
}

To be able to query a database or any other storage we will need an implementation of Specification. Here it goes (couple of them, actually):

Specifications are really simple and in most cases has only one method. You can add as many Specifications as you want, without modifying DAO classes. Moreover testing is simpler. We stick to interfaces, so it can be easily mocked and replaced. You can provide some fake data too, while mapping Repository itself. Can you imagine how those Specification classes are easy to read comparing to veryyyy long DAO?

Repository fits quite good to MVP, but can be easily used in other classes too. By using Dagger you need to define which implementation of Repository you want to use in one place.

Let’s complicate it a little bit

OK. Requirements has changed. You can no longer use SQLite. You’re cool and therefore you’ll be using Realm.

// me waiting for your yelling

What happens when you’ve implemented application by using DAOs? You have to refactor a tons of classes, even those not related to data access layer. This is not going to happen when Repository Design Pattern is your friend, though. All what you need to do is to implement Repository and Specifications to fit new requirements (let’s stick to Realm). That’s all. You will not be digging in other classes. Take a look at brand new implementation:

There is a new Specification, as well:

public interface RealmSpecification extends Specification {
RealmResults<NewsRealm> toRealmResults(Realm realm);
}

And an example implementation of just created RealmSpecification:

Now, you’re ready to use Realm instead of SQLite without modifying any unrelated class (do you remember how dependency has been defined in Presenter?).

Bonus

There is also one more extra use case. You can use RDP also to provide caching — as on the previous example, just create CacheSpecification e.g.:

public interface CacheSpecification<T> extends Specification {
boolean accept(T item);
}

and use it along with others:

What’s important, not all of your specifications need to implement all interfaces. If only NewsByIdSpecification is used while caching, there is no need to implement CacheSpecification by NewsByCategorySpecification.

Your code is cleaner now, your teammates love you, kittens not gonna die, and even if you left company the next guy will not kill you, even if he’s psychopath.

#ArchitectureMatters