Skip to content

Tableview datasources and the decorator pattern

Fair warning: Coming up with an example relevant enough to illustrate the topic, but simple enough to fit in about 1500 words is challenging. Take this code as a starting point, as a way to illustrate a discussion, and not as a drop-in solution ready to apply to a codebase.

Also, this solution can be applied to collection views. But again, for brevity, I will only discuss table views.

The previous post in this very blog was about going from the abstract and generic to the concrete and specific. It was, in a way, about specialising something abstract and generic, by subclassing it and providing a specific implementation for a specific type.

The sample code I used was more or less copied and pasted (with some info removed to protect the innocent) from the codebase I am currently maintaining. At the time I posted it it was holding well, but soon after that post I started having the feeling that there had to be a better way.

The problem

The problem I am trying to solve is a fairly common problem when it comes to iOS development: presenting lists of data without having an a lot of boilerplate code repeated again and again.

The usual way to present a list would be having a UIViewController that implements some or all of the methods in UITableViewDataSource.

That could be fine if there was only one data collection to render on screen, but usually, iOS apps are a sequence of screens that present data collections. Not only that, but usually, those screens are not that different from each other.

Sometimes, what changes from one data screen to another is the way a data item is rendered on screen (different UITableViewCells), some other times what changes from one screen to another is the presence or absence of section headers, or section footers, or both headers and footers.

So, if we approach the problem trying to abstract it as much as possible, what we would have would be a core behaviour (presenting data) that we might want to customise (i.e. adding headers or footers). And to make things more interesting, we want to do that in a way that reduces boilerplate and duplication and makes the solution testable.

The solution I have been exploring

The first step would be finding a way to factor out data management from view controllers. First, because it makes sense (a view controller should control a view, not manage a collection of data), and second, because by doing so we can remove a lot of boilerplate and duplication.

Shameless self promotion here: some time ago I published a framework to do precisely that.

There are other solutions, but I am sticking to mine for now, not because I think it’s better, but because, so far, it works for me. Basically, the implementation of the UITableViewDataSource protocol does not populate cells outlets, but provides cells with a model object, and trusts cells to know how to render that model object themselves. Tell, don’t ask!

So let’s start there. Let’s assume we are working on a task manager. We have a Task:

And we have a class to manage tasks as flat arrays. In real life, this data manager should be able to handle sections, but, again, for brevity, this one will be all flat:

Now, let’s move to the other end of the problem: the UI. As mentioned, cells will know what to do to render themselves when they are provided with data. We can model that assumption with a protocol that indicates that a cell will accept a model object, and a concrete implementation of that protocol:

A class implementing the required methods in UITableViewDataSource will look like this:

We provide it with a data manager, and a cell type. Notice how the implementation of the cellForRowAtIndexPath method only dequeues the cell, and passes it the model object that corresponds to its index.

So far, none of this solves the actual problem: customising data listings. But it send the foundation for a solution.

What was the problem again?

Let’s say that we have to render two different task lists, one of them without any section headers, and another one with a single section header. Let’s say also that we need a third listing with a section footer.

If we go all abstract, what we want is our datasource to behave slightly differently in different situations, while maintaining a core behaviour unchanged. Or, in other words, what we want is to add behaviour to an individual object without affecting the behaviour of other objects of the same class.

The Decorator Pattern

And that is, literally, the definition of the Decorator Pattern. So, let’s explore the Decorator Pattern a little bit more, and see if it can actually be a good solution to our problem.

(UML taken from wikipedia)

The pattern’s intent is clear: extending the behaviour of a certain object, independently of other instances of the same class. That will fit our case: we want some behaviour to remain unchanged but we also want to be able to customise some other behaviours, but only for specific cases.

There is another subtle detail here: the core behaviour, what we do not want to change, happens to be what is provided by the required methods in the UITableViewDataSource protocol, and what we want to customise, happens to be declared in optional methods.

That fits the pattern quite well. The ConcreteComponent could provide the behaviour we don’t want to change, provided by the require methods in the UITableViewDataSource protocol, and we could add ConcreteDecorators for each behaviour we wanted to add or customise.

So, just to recap, there seems to be a one to one relationship between the elements of the pattern and our use case: the Component would be the UITableViewDataSource protocol, the ConcreteComponent would be the Required class, and we can provide ConcreteDecorators that also implement the UITableViewDataSourceProtocol.

Let’s get to it!

This is the starting point:

We would also need an implementation of the UITableViewDataSource protocol that aggregates an instance of the UITableViewDataSource type, implements all the methods in the protocol and forwards them to the instance it aggregates:

And now we can start encapsulating the different behaviours we want to provide in subclasses of that TableDecorator. For example, if we need to provide a header title for a single section, a footer title for a single section, and header titles for multiple sections:

The beauty of this solution is that now we can add behaviours to the core behaviour of our datasource, in a composable way. Each behaviour would be well encapsulated, which in turn means that it can be easily tested, and it could also be reused eventually.

And what is even better is that we can mix and match behaviours without modifying the code in the core datasource, and without adding any conditional logic.

For example, if we want a table with section header and no footer, we can do this:

But if we want a table with header and section header and footer we can do this:

And if for some reason we wanted a table with a section header that is a slight modification of the previous one, we could just add another decorator like this:

That is the way we can compose optional behaviours: by adding them one by one, as layers of an onion, to a core behaviour.

Final words

I have ambivalent feelings about Design Patterns. I do agree that these patterns tend to be overused, and I have found myself a few times at that stage where all you can see are design patterns everywhere, and you try to solve any possible problem with an implementation of the Visitor Pattern.

But if design patterns are taken as what I believe they are, which is just one more tool, being able to identify them, and being able to consider the trade-offs of implementing or not implementing them can make a huge difference in the quality of a codebase.

In this particular example, having a collection of highly cohesive, loosely coupled and highly testable behaviours, that can be applied to modify a core behaviour at will, seems like a win.

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *