Design Principles: Single Responsibility Principle

Design Principles: Single Responsibility Principle

Tags
Software Development
Design
Published
December 3, 2024
Author
Mohit Srivastava
In the ever-evolving world of software development, writing clean, maintainable, and scalable code is paramount. One way to achieve this is by adhering to fundamental design principles that guide developers in structuring their code effectively. This blog post delves into basic design principles, focusing on the Single Responsibility Principle (SRP), and illustrates how to apply it using a simple Book Invoice Application example.
 
Why Design Principles Matter
Design principles serve as foundational guidelines that help developers create software with these essential qualities:
  • Maintainable: Easy to understand and modify
  • Scalable: Able to grow and handle increased demands
  • Robust: Resistant to errors and bugs
  • Reusable: Components that work across different parts of the application or in other projects
Following these principles helps developers avoid common pitfalls like code duplication, tight coupling, and unnecessary complexity—ultimately leading to more efficient development.
 
The Single Responsibility Principle (SRP)
The Single Responsibility Principle is one of the five SOLID principles of object-oriented design. It states that:
A class should have one, and only one, reason to change.
In essence, each class or module should focus on a single task or responsibility. This separation of concerns makes the codebase easier to manage, test, and extend.
Lets us understand this principle using a example of Book Invoice Application
We have two classes Book and Invoice. Book has all information about books and Invoice has following functionality:
  • Calculate price of a book
  • Print invoice
  • Save invoice to a database
 
Initial Design
Initially, the Invoice class handles multiple responsibilities:
  • Calculating the price of a book
  • Printing the invoice
  • Saving the invoice to a database
classDiagram class Book { - String title - String author - double price + getTitle() + getAuthor() + getPrice() } class Invoice { - Book book - int quantity + calculateTotalPrice() + printInvoice() + saveToDatabase() } Book "1" <-- "*" Invoice : contains
 
Identifying the Problem
The Invoice class violates the SRP by handling more than one responsibility:
  • Business Logic: Calculating the total price.
  • Presentation Logic: Printing the invoice.
  • Persistence Logic: Saving to the database.
 
Refactored Design to follow SRP
  • Invoice: Handles invoice data and price calculation.
  • InvoicePrinter: Manages the formatting and printing of invoices.
  • InvoiceDatabase: Handles saving invoices to the database.
classDiagram class Book { - String title - String author - double price + getTitle(): String + getAuthor(): String + getPrice(): double } class Invoice { - Book book - int quantity + getBook(): Book + getQuantity(): int + calculateTotalPrice(): double } class InvoicePrinter { + printInvoice(Invoice invoice): void } class InvoiceDatabase { + saveToDatabase(Invoice invoice): void } Book "1" <-- "*" Invoice : contains InvoicePrinter ..> Invoice : uses InvoiceDatabase ..> Invoice : uses
 
We will discuss other design principles in upcoming blog sections