SOLID Principle: Single Responsibility Principle

Tram Ho

This is the first of five parts of the SOLID principle series

SOLID is a simple way to help us remember the five basic design principles of object orientation

  • Single Responsibility Principle (this article)
  • Open-Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

In the following sections, I will dive into each principle, explain it and how it applies in Android development. By the end of the series, you will have a firm grasp of the principles of why they are important to an Android developer and how you can apply them at work.

The Single Responsibility Principle

The Single Responsibility Principle (SPR) is fairly easy to understand. It states the following

A class should have only one reason to change

Take the case of a RecyclerView and its adapter. As you probably know, a RecyclerView is a flexible view capable of displaying a data set on the screen. For this data to be displayed on the screen, we need a RecyclerView adapter.

An adater takes data from the data set and joins it into a view. The most used part of the adapter is the onBindViewHolder method (and sometimes onBindViewHolder itself, but they describe only the analysis onBindViewHolder for a short message). The Recyclerview adapter has a task: mapping an object to its corresponding view that will be displayed on the screen.

Assume the object and RecyclerView.Adapter are as follows:

In the above code, onBindViewHolder empty. An implementation I have seen many times may look like this:

The above code violates the Single Resposibility Principle

Why

The Adapter’s onBindViewHolder method not only maps an Order object to the view, it also handles the price calculation as well as format it. This violates the Single Responsibility Principe. The adapter should only be responsible for assembling an order object to its corresponding view. onBindViewHolder is doing two more tasks that it shouldn’t perform.

Why is this a problem?

Leaving a class accountable may be the cause of many problems. First, the logical calculation in the order is now appended to the adapter. If you need to display the total of an order somewhere else (this is very likely) you will have to redo that logic. Once this happens, your application will face the logical iteration problem we are familiar with. You updated the code in one place and forgot to update it elsewhere etc. ..

The second problem is the same as the first – you merge the format logic into the adapter. What happens if a migration or update is needed? At the end of the day, we made this class do more than it needed, and now the application is vulnerable to bugs because there are so many responsibilities in one place.

Thankfully, this simple example can be easily overcome by calculating the total inside the Order object and we will move the format logic into the formater class of that type. Formatter can then be used by Order as well.

An updated of the onBindViewHolder method will look like this:

I’m sure you will think “Ok, this is easy”. Is it always easy? As most answers in the software – “It will depend on the scope”

Let’s dig a little deeper.

“What does responsiveibility mean?”

It’s hard to define it better than Uncle Bob, so I’ll quote him here:

In the context of the Single Responsibility Principle (SRP) we define a responsibility as a reason for change. If you can think of more than one excuse to change a class, this class has more than one responsibility.

The problem is, this is sometimes really hard to identify – Especially if you’ve been in the codebase for a long time. At that time, this famous quote often came to mind:

You can’t see the forest for the trees.

In the context of software, this means you are too close to your detailed code to see the bigger picture. For example – the class you are working on might look great but it’s because you’ve been working with it for so long, it’s hard to see that it has a lot of responsibility.

The challenge is to know when to apply SRP and when not. Taking the example of adapter sample above, if we look back at the code, we can see many things happening that might require changing areas other than for other reasons.

The adapter is inflating a view, it binds an order to a view, it constructs the view holder, etc. This class has many responsibilities

There is need to tear down these resposibility.

This ultimately depends on how the application changes over time. If the application changes in such a way that the views fit together and its connecting functons (the logic of the view) when one view changes, another view will need to be changed. A change of the view structure also requires a change of the adapter itself, so this design becomes hard. However, it can also be argued that if the application does not change in ways that require different capabilities to change at different times, then there is no need to separate them. In this case, splitting them will add unnecessary complexity.

So what to do?

An example to illustrate

Imagine that there is a new requiment when the total payment for an order is 0, the view displays a color image with the word “FREE” on the screen instead of the text to display the total amount. Where is the logic? In code, you need a TextView, and in other cases you need an ImageView. There are 2 locations where the code needs to be changed:

  1. In view
  2. In presentation logic.

But with most applications I’ve seen, this is done in the adapter. Unfortunately, this causes the Adapter to change as your view changes. If the logic for this is in the adapter, this changes the logic of the apdater, as well as the code for the view. This adds an extra responsibility to the adapter.

This is exactly something like the Model-View-Presenter pattern that provides the separation necessary so that layers don’t become too rigid, but still provide flexibility for extension, composability and testing. For example, the view implements an interface that defines how it will interact, and the presenter will handle the necessary logic. The presenter in the Model-View-Presenter pattern is only responsible for handling display logic, nothing more.

Moving these logic from the apdater into the presenter will make the adapter more compliant with the single responsible principle.

Those things are not enough …

If you look deeply into any RecyclerView adapter, you most likely notice that adapters do many things, Things adapters still do.

  • Inflate view
  • Initialize ViewHolder
  • Reuse View Holder
  • Provide item count
  • ect

Since SRP is about single responsibility, you might be wondering if some of these behaviors should be brought out to comply with the SPR.

While the Adapter still handles many different actions, but in fact, that is what it is designed to perform. After all, the same RecyclerView adapter is simply an implementation of the Adapter pattern. In this case, keeping inflation and view holders in the adapter makes sense, which is what this class is responsible for and that’s what it does best. However, adding other vi rows (such as logic) breaks SPR and can be avoided by using Mode-View-Presenter or other refactor methods.

Conclude

Thank you for watching. Thank you

Refer

https://academy.realm.io/posts/donn-felker-solid-part-1/

Share the news now

Source : Viblo