SOLID - Single Responsibility Principle

Solid Principles

Next →

In this tutorial we are going to learn about the Single Responsibility Principle (SRP).

Table of contents

GitHub repository

Reference

  • S Single Responsibility Principle
  • O Open-Closed Principle
  • L Liskov Substitution Principle
  • I Interface Segregation Principle
  • D Dependency Inversion Principle

Definition

Single Responsibility Principle (SRP) states that a class should have only one responsibility and hence should have only one reason to change.

Example

Consider the following Java program. We have a MegaPayment class which contains the following methods.

class MegaPayment {
  public String makePayment() {
    // do something...
    return "Payment done!";
  }

  public String getPaymentStatusById(String paymentId) {
    // do something...
    return "Current status of Payment Id " + paymentId + " is PAID.";
  }

  public String getGiftCardBalanceById(String giftCardId) {
    // do something...
    return "Current balance of Gift card Id " + giftCardId + " is 10.";
  }

  public double getDiscount() {
    // do something...
    return 10;
  }
}

This class has the following responsibilities.

  • It is making payment using the makePayment method.
  • It is getting the status of a payment using the getPaymentStatusById method.
  • It is also getting the balance of a gift card using the getGiftCardBalanceById method.
  • And it is also computing the discount using the getDiscount method.

Problem

We can clearly see that the MegaPayment class has more than one responsibility. Each time we need to make changes to discount logic or payment logic or gift card balance logic we would have to come to this class and make changes to it. Hence this class has more than one reason to change and this is clearly breaking the Single Responsibility Principle.

Imagine having this class in a real project with hundreds and thousands of lines of code. Classes like these with too many responsibilities are harder to maintain and very difficult to understand. To fix this class we have to break the it into more meaningful and focused classes that have only one responsibility and hence only one reason to change.

Solution

public class PaymentService {
  public String makePayment() {
    // do something...
    return "Payment done!";
  }

  public String getPaymentStatusByPaymentId(String paymentId) {
    // do something...
    return "Current status of Payment Id " + paymentId + " is PAID.";
  }
}


class GiftCardService {
  public String getGiftCardBalanceById(String giftCardId) {
    // do something...
    return "Current balance of Gift card Id " + giftCardId + " is 10.";
  }
}


class DiscountService {
  public double getDiscount() {
    // do something...
    return 10;
  }
}

We have now divided the MegaPayment class into three separate classes as per responsibility.

Note! Only one responsibility or only one reason to change does not necessarily mean that a class will have only one method. What it implies is that the class should be focused on doing things that are closely related. For example, the GiftCardService class can have methods like getBalance and setBalance as they are related tasks. However, it should not be concerned with computing discounts for different payment methods like Credit Card, Debit Card, Cash-on-Delivery, etc.

Next →