Single Responsibility Principle

About a year ago I was asked to do a talk covering the SOLID principles of Object Oriented Programming (OOP) at my local Laravel Meetup. We recently had another meetup after a 9 month hiatus, and there were several new members who showed some interest in the topic. So I thought i would turn my talk into 5 blog posts covering each rule.

The Single Responsibility Principle, is the first SOLID Principle for OOP.

For those new to SOLID, S.O.L.I.D Stands for:

Single Responsibility Principle

Open Closed Principle

Liskov Substitution Principle

Interface Segregation Principle

Dependency Inversion Principle

This article is the first of a 5 post series that will cover the SOLID Principles.

A Class should have only one reason to change, meaning that a class should have only one job.

In this Principle you want to make sure your classes are only responsible for a single thing. Think of a thing as a type of Object. If you were to instantiate a class as an object, the methods on that object should really only apply to the type of object it is. For instance the most popular example of an object might be a Car. A car should only have methods that would allow a Car to do something a Car can do. For instance, accelerate, brake, turn left, turn right. Those are all things a car can do. You wouldn't expect to see a method on the Car Object that figures out distance from point A to point B. Even though a car can certainly travel that distance, it's not a cars Responsiblity to calculate distance.

So let's look at some examples that don't involve cars. Let's use a Garden as an example.

A garden is made up of lots of different types of plants.

A garden by it's self is an Object that's made up of lots of other Objects as plants. For instance a garden can have Lettuce, carrots, etc.

In our Garden class we accept an array of plants in our constructor, and we have a method to calculate the quantity of plants we have in our garden.

You'll note that our quantity() method is checking to see if the plant type is a root vegetable or not. If it is, it's using the perBunch variable to multiply the count variable to get an accurate count of carrots.

For the sake of this example we'll assume Broccoli's are not root vegetables.
Now when we do $garden->quantity(); we should get 22. So far our Carrot class is only responsible for Carrot things, and our Garden class is only responsible for garden things.

Now here's where things get complicated. Let's say we want to have several different formats for the output of our quantity() method on our Garden Class. Say we want just the numerical value for processing in code, json for processing an API response, and HTML for sending pre-formatted output to a View.

Now here's where the Single Responsibility Principle throws a red flag.
You'll remember in the beginning of the article we talked about how a class should only have one reason to change, a single job.

Well our Garden class now has two jobs. It has the job of keeping track of what's in our garden, but it also has the job of formatting the response now as well. Meaning the class has to change each time we want to expand our garden methods, but it also has to change every time we want to add/change/remove formatting options as well.

So how do we change this? Well, we need to build another class that manages just formatting, and pass the garden class to it, similar to how we pass our plant classes to our garden class.

with out defining the GardenOutputterclass, what we end up with is something like the following: