Is Content Provider an implementation of Repository Pattern?

Short answer: a Contentprovider is a datasource and not a repository.

The purpose of SQL-Database/Android-Contentproviders/Repositories is to create/read/update/delete/find data

Repositories usually operate on high level busines specific java classes (like Customer, Order, Product, ....) while SQL-Database and Android-Contentproviders operate on low level table, rows and colums as a datasource.

Because a SQL-Database is not a repository so an Android-Contentprovider is not a repository, too.

But you can implement a repository by using an underlying Contentprovider


Kudos for the question, it's a nice observation :). IMHO, this is not a yes or no question because it is quite general, as most design patterns related topics are. The answer is depending on what context are you taking in account:

If you have an app that relies entirely on the platform, meaning that take into account only the context of the Android ecosystem, then yes, the ContentProvider IS an implementation of the Repository pattern. The argument here it is that the content provider was designed to solve some of the same challenges that the repository patterns aim to solve:

  • It provides abstraction over data layer, so the code is not necessarily dependent on the storage environment
  • No direct data access from everywhere. You can put all your SQL queries (or whatever) in a single place. When I first implemented a ContentProvider as a noob, it was like a revelation to me how clean my code can look like and how comfortable I can be doing changes
  • Centralizes the data and shares it between multiple clients (other apps, a search widget as you already know) and provides mechanism for data security
  • You can definitely define data related behavior (one way is by using ContentObserver)
  • It's a pretty good way to force you from the early stages to organize your code with unit testing/ automated testing in mind

If you put all of above side by side with the principles of the repository pattern, there are some serious similarities. Not all of them are satisfied, but the core ideas are the same.

Now, considering an app working on a larger scale in multiple environments (i.e web, mobile, PC) the requirements change completely. It is a bad idea as everyone suggested to rely on the ContentProvider as a design pattern. It's not necessarily a bad idea in itself, but a design pattern must be implemented so others can understand your code as fast as possible. You see, even here everyone suggested a common use of ContentProvider: as a datasource, or anyhow something platform dependent. So if you force an implementation on top of a component with known purpose, things can become rather unclear. It's much nicer to organize your code in a classical pattern.

tl;dr; If your app is isolated on your Android device you can definitely merge the two concepts. If your app is used on a larger scale, on multiple platforms it's cleaner, to organize your code in a classical manner.


Let's try to compare the Repository Pattern definition from the book "Patterns of Enterprise Application Architecture" by Martin Fowler (with Dave Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, and Randy Stafford) with what we know about ContentProviders.

The book states:

A Repository Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

The important bit is accessing domain objects. So at first glance it seems that the repository pattern is only meant for accessing (querying) data. With a ContentProvider, however, you not only can access (read) data but also insert, update or remove data. However, the book says:

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.

So, yes Repository and ContentProvider seem to offer the same operations (very high level point of view) although the book explicitly states simple collection of objects which is not true for ContentProvider as it requires android specific ContentValues and Cursor from Client (who uses a certain ContentProvider) to interact with.

Also, the book mentions domain objects and data mapping layers:

A Repository Mediates between the domain and data mapping layers

and

Under the covers, Repository combines Metadata Mapping (329) with a Query Object (316) Metadata Mapping holds details of object-relational mapping in metadata.

Metadata Mapping basically means i.e. how to map a SQL column to a java class field.

As already mentioned ContentProvider returns a Cursor object from a query() operation. From my point of view a Cursor is not a domain object. Moreover, mapping from cursor to domain object must be done by the client (who uses a ContentProvider). So data mapping is completely missing in ContentProvider from my point of view. Furthermore, the client may have to use a ContentResolver too to get the domain object (data). In my opinion this API is a clear contradiction with the definition from the book:

Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers

Next let's focus on the core idea of the Repository pattern:

In a large system with many domain object types and many possible queries, Repository reduces the amount of code needed to deal with all the querying that goes on. Repository promotes the Specification pattern (in the form of the criteria object in the examples here), which encapsulates the query to be performed in a pure object-oriented way. Therefore, all the code for setting up a query object in specific cases can be removed. Clients need never think in SQL and can write code purely in terms of objects.

ContentProvider requires a URI (string). So it's not really a "object-oriented way". Also a ContentProvider may need a projection and a where-clause.

So one could argue that a URI string is some kind of encapsulation as the client can use this string instead of writing specific SQL code for instance:

With a Repository, client code constructs the criteria and then passes them to the Repository, asking it to select those of its objects that match. From the client code's perspective, there's no notion of query "execution"; rather there's the selection of appropriate objects through the "satisfaction" of the query's specification.

ContentProvider using a URI (string) doesn't seem to contradict with that definition, but still misses the emphasized object-oriented way. Also strings are not reusable criteria objects that can be reused in a general way to compose criteria specification to "reduces the amount of code needed to deal with all the querying that goes on."

For example, to find person objects by name we first create a criteria object, setting each individual criterion like so: criteria.equals(Person.LAST_NAME, "Fowler"), and criteria.like(Person.FIRST_NAME, "M"). Then we invoke repository.matching(criteria) to return a list of domain objects representing people with the last name Fowler and a first name starting with M.

As you have already said (in your question) Repository is also useful to hide different data sources as an implementation detail the client doesn't know about. This is true for ContentProviders and specified in the book:

The object source for the Repository may not be a relational database at all, which is fine as Repository lends itself quite readily to the replacement of the data-mapping component via specialized strategy objects. For this reason it can be especially useful in systems with multiple database schemas or sources for domain objects, as well as during testing when use of exclusively in-memory objects is desirable for speed.

and

Because Repository's interface shields the domain layer from awareness of the data source, we can refactor the implementation of the querying code inside the Repository without changing any calls from clients. Indeed, the domain code needn't care about the source or destination of domain objects.


So to conclude: Some definitions from Martin Fowler et al. book match the API of a ContentProvider (if you ignore the fact that the book emphasized object-oriented):

  • Hides the fact that a repository / ContentProvider has different data sources
  • Client never has to write a query in a datasource specific DSL like SQL. That is true for ContentProvider if we consider URI as not datasource specific.
  • Both, Repository and ContentProvider, have the same "high level" set of operations: read, insert, update and remove data (if you ignore the fact that Fowler talks a lot about object orientated and collection of objects whereas ContentProvider uses Cursor and ContentValues)

However, ContentProvider really misses some key points of the repository pattern as described in the book:

  • Since ContentProvider uses URI (also string for the where clause) a client can't reuse Matching Criteria objects. That is an important thing to note. The book clearly says that the repository pattern is useful "In a large system with many domain object types and many possible queries, Repository reduces the amount of code needed to deal with all the querying that goes on". Unfortunately, ContentProvider doesn't have Criteria objects like criteria.equals(Person.LAST_NAME, "Fowler") that can be reused and used to compose matching criterias (since you have to use strings).
  • ContentProvider miss entirely data mapping as it returns a Cursor. This is very bad because a client (who uses a ContentProvider to access data) has to do the mapping of Cursor to domain object. Furthermore, that means that client has knowledge of repository internals like name of columns. "Repository can be a good mechanism for improving readability and clarity in code that uses querying extensively." That certainly is not true for ContentProviders.

So no, a ContentProvider is not a implementation of the Repository pattern as defined in the Book "Patterns of Enterprise Application Architecture" because it misses at least two essential things I have pointed out above.

Also, please note that as the name of the book already suggests, the repository pattern is meant to be used for Enterprise Application where you do a lot of queries.

Android developers tend to use the term "Repository pattern" but don't actually mean the "original" pattern described by Fowler et al. (high reusability of Criterias for queries) but rather mean a interface to hide the underlying data source (SQL, Cloud, whatever) and domain object mapping.

More here: http://hannesdorfmann.com/android/evolution-of-the-repository-pattern


I'll mention Dianne Hackborn (from Android Framework team) to give my opinion.

ContentProvider

Finally, the ContentProvider is a fairly specialized facility for publishing data from an app to other places. People generally think of them as an abstraction on a database, because there is a lot of API and support built in to them for that common case... but from the system design perspective, that isn't their point.

What these are to the system is an entry-point into an app for publishing named data items, identified by a URI scheme. Thus an app can decide how it wants to map the data it contains to a URI namespace, handing out those URIs to other entities which can in turn use them to access the data. There are a few particular things this allows the system to do in managing an app:

• Handing out a URI doesn't require the app remain running, so these can go all over the place with the owning app being dead. Only at the point where someone tells the system, "hey give me the data for this URI" does it need to make sure the app owning that data is running, so it can ask the app to retrieve and return the data.

• These URIs also provide an important fine-grained security model. For example, an application can place the URI for an image it has on the clipboard, but leave its content provider locked up so nobody can freely access it. When another app pulls that URI off the clipboard, the system can give it a temporary "URI permission grant" so that it is allowed to access the data only behind that URI, but nothing else in the app.

What we don't care about:

It doesn't really matter how you implement the data management behind a content provider; if you don't need structured data in a SQLite database, don't use SQLite. For example, the FileProvider helper class is an easy way to make raw files in your app available through a content provider.

Also, if you are not publishing data from your app for others to use, there is no need to use a content provider at all. It is true, because of the various helpers built around content providers, this can be an easy way to put data in a SQLite database and use it to populate UI elements like a ListView. But if any of this stuff makes what you are trying to do more difficult, then feel free to not use it and instead use a more appropriate data model for your app.

Full text here: https://plus.google.com/+DianneHackborn/posts/FXCCYxepsDU