You are now reading the second part of my blog series on the SOLID principles. In the first post I introduced the concept and gave some reasons to why you should learn about SOLID. In this part I will write about the first of the five SOLID principles, the Single-Responsibility Principle (SRP).
The Single-Responsibility Principle states that ”A class should have only one responsibility” or ”A class should have only one reason to change”.
This means that, if you need to change a class for more than one reason, it has multiple responsibilities, and therefore violates SRP.
There are a couple of different code smells that might appear due to violation of SRP. These are:
- Fragility – If a class has more than one responsibility, classes that should not be related becomes coupled. Changes related to one of the responsibilities may break the application in unexpected ways.
- Rigidity – Changes related to one responsibility may force classes depending on other responsibilities to be re-compiled / re-deployed, making the application harder to change.
How to apply
NOTE: It is not wise to apply SRP, or any other principle for that matter, if there is no symptom! Only once you have identified that there are changes being made and it is troublesome, then it should be fixed.
The most obvious way to apply SRP is to separate implementation of the identified responsibilities into different classes. This might however not be possible due to details of the hardware or the operating system. There are however a few patterns that can help. Though not all of them may apply to your specific implementation, I will list them here for you and you should be able to decide if it is good fit for you.
The Facade Pattern
The Facade Pattern is used when you want to provide a simple and specific interface onto a group of objects that have a complex and general interface.
Assume that it is not possible to split up the implementation, so you are stuck with a complex, multi responsibility object. You can then create simple interfaces each cover a single responsibility of the implementation. Users then only have to care about the methods of that specific interface.
Data Access Object
In the case where business logic and persistence functionality have been mixed into a single class (for example if you have a Product class with it’s data fields that also knows how to read and write to the database) the responsibility of database access can be moved to a Data Access Object (DAO).
To implement this you create an interface for CRUD operations towards the database, for the specific business logic. Then you create a separate implementation, removing the persistence logic/responsibility from the business logic class.
The Proxy Pattern
The Proxy Pattern is another way to separate, for example, persistence logic from business logic. Proxies are not trivial to implement but provide good separation. I recommend that you do read up on the proxy pattern, and the other patterns as well, from different sources and look at a few examples before implementing it in your own code.
Assume again that you have business logic and database logic mixed in the same class. In short, the proxy pattern is implemented by breaking up the current implementation into three parts:
- An interface
- Business logic
- Database aware logic
Both the business logic and the database aware logic will implement the interface. The database logic will be aware of the business logic class and have the responsibility of accessing the database. The business logic will now however have no dependency to the database.
The database aware logic will work as a proxy for the business logic. Users can be handed and use the proxy, and since the interface is the same as for the business logic, they can treat it as a normal business logic object, happily unaware of that it accesses the database under the surface.
The Single-Responsibility Principle is easy to understand, but hard to get right. The reason being we naturally group responsibilities together.
After reading this post you hopefully have some ideas what to look out for and how to tackle the issues. I am also quite certain that you will need to read a bit more, see some code examples, and work a bit with your code before you start feeling comfortable with applying SRP.
In the next post we will be looking into the next principle of SOLID, the Open/Closed Principle (OCP).