Chapter 8: SOLID Principles & Design Patterns


Introduction

As software systems grow, maintaining and extending code becomes increasingly difficult.

Enterprise applications often suffer from:

  • Tight Coupling
  • Duplicate Code
  • Complex Dependencies
  • Difficult Testing
  • Poor Maintainability

To solve these problems, software engineers use:

  • SOLID Principles
  • Design Patterns

These concepts help developers build applications that are:

  • Maintainable
  • Scalable
  • Flexible
  • Testable
  • Extensible

In this chapter, we will learn the five SOLID principles and several commonly used design patterns while applying them to our Institute Placement Management System (IPMS).


What You Will Learn

By the end of this chapter, you will:

  • Understand SOLID Principles
  • Apply Single Responsibility Principle
  • Apply Open Closed Principle
  • Apply Liskov Substitution Principle
  • Apply Interface Segregation Principle
  • Apply Dependency Inversion Principle
  • Understand Design Patterns
  • Implement Singleton Pattern
  • Implement Factory Pattern
  • Implement Builder Pattern
  • Implement Strategy Pattern
  • Apply Enterprise Design Practices

Understanding SOLID

SOLID is a collection of five design principles.


SOLID Overview

S - Single Responsibility Principle

O - Open Closed Principle

L - Liskov Substitution Principle

I - Interface Segregation Principle

D - Dependency Inversion Principle

SOLID Principles Overview

SOLID Principles Overview


Single Responsibility Principle (SRP)

A class should have only one reason to change.


Poor Design

public class StudentService {

    public void registerStudent() {

    }

    public void sendEmail() {

    }

    public void generateReport() {

    }
}

Problems

  • Multiple Responsibilities
  • Difficult Maintenance
  • Difficult Testing

Better Design

public class StudentService {

    public void registerStudent() {

    }
}

public class EmailService {

    public void sendEmail() {

    }
}

public class ReportService {

    public void generateReport() {

    }
}

IPMS Example

StudentService

Responsible for:

Student Operations

NotificationService

Responsible for:

Notifications

Open Closed Principle (OCP)

Software entities should be:

Open for Extension

Closed for Modification

Poor Design

public class ReportGenerator {

    public void generate(
            String type) {

        if(type.equals("PDF")) {

        }
        else if(type.equals("EXCEL")) {

        }
    }
}

Better Design

public interface ReportGenerator {

    void generate();
}

PDF Report

public class PdfReportGenerator
        implements ReportGenerator {

    @Override
    public void generate() {

    }
}

Excel Report

public class ExcelReportGenerator
        implements ReportGenerator {

    @Override
    public void generate() {

    }
}

Usage

ReportGenerator report =
        new PdfReportGenerator();

Liskov Substitution Principle (LSP)

Subclasses should be replaceable by parent classes.


Example

User user =
        new Student();

Valid Substitution

User user =
        new Recruiter();

Invalid Design

class Bird {

    void fly() {

    }
}

class Penguin
        extends Bird {

}

Penguins cannot fly.

LSP violation.


Better Design

interface Bird {

}

interface FlyingBird
        extends Bird {

    void fly();
}

Interface Segregation Principle (ISP)

Clients should not depend on methods they do not use.


Poor Design

public interface Worker {

    void work();

    void eat();

    void drive();
}

Problems

Not every worker drives.


Better Design

public interface Workable {

    void work();
}

public interface Eatable {

    void eat();
}

public interface Drivable {

    void drive();
}

Dependency Inversion Principle (DIP)

Depend upon abstractions, not concrete classes.


Poor Design

public class StudentService {

    private EmailService emailService =
            new EmailService();
}

Better Design

public interface NotificationService {

    void send();
}

public class EmailService
        implements NotificationService {

    @Override
    public void send() {

    }
}

public class StudentService {

    private NotificationService
            notificationService;
}

SOLID in IPMS

SOLID in IPMS


Introduction to Design Patterns

Design Patterns are proven reusable solutions to common software design problems.


Categories

  • Creational
  • Structural
  • Behavioral

Pattern Classification

Creational

Structural

Behavioral

Common Enterprise Patterns

  • Singleton
  • Factory
  • Builder
  • Strategy

Singleton Pattern

Ensures only one object exists.


Use Cases

  • Configuration
  • Logging
  • Cache
  • Settings

Singleton Example

public class ConfigurationManager {

    private static
    ConfigurationManager instance;

    private ConfigurationManager() {

    }

    public static
    ConfigurationManager
    getInstance() {

        if(instance == null) {

            instance =
                    new ConfigurationManager();
        }

        return instance;
    }
}

Usage

ConfigurationManager config =
        ConfigurationManager
                .getInstance();

Singleton Architecture

Singleton Pattern


Factory Pattern

Creates objects without exposing creation logic.


Example Interface

public interface NotificationService {

    void send();
}

Email Service

public class EmailService
        implements NotificationService {

    @Override
    public void send() {

    }
}

SMS Service

public class SmsService
        implements NotificationService {

    @Override
    public void send() {

    }
}

Factory Class

public class NotificationFactory {

    public static
    NotificationService create(
            String type) {

        if(type.equals("EMAIL")) {

            return new EmailService();
        }

        return new SmsService();
    }
}

Usage

NotificationService service =
        NotificationFactory
                .create("EMAIL");

Builder Pattern

Used for constructing complex objects.


Student Object

public class Student {

    private Long id;

    private String name;

    private String email;

    private double cgpa;
}

Builder Example

Student student =
        new StudentBuilder()
                .id(101L)
                .name("John Doe")
                .email("john@example.com")
                .cgpa(8.75)
                .build();

Benefits

  • Readability
  • Flexibility
  • Immutability Support

Strategy Pattern

Allows interchangeable algorithms.


Example

Placement Eligibility Calculation.


Strategy Interface

public interface EligibilityStrategy {

    boolean eligible(
            Student student);
}

CGPA Strategy

public class CgpaStrategy
        implements EligibilityStrategy {

    @Override
    public boolean eligible(
            Student student) {

        return student.getCgpa() >= 7;
    }
}

Backlog Strategy

public class BacklogStrategy
        implements EligibilityStrategy {

    @Override
    public boolean eligible(
            Student student) {

        return student.getBacklogs() == 0;
    }
}

Using Strategy

EligibilityStrategy strategy =
        new CgpaStrategy();

Execute Strategy

strategy.eligible(student);

Design Pattern Overview

Design Pattern Overview


IPMS Student Registration Design

StudentController
        ->
StudentService
        ->
StudentRepository

IPMS Notification Design

NotificationFactory
        ->
EmailService
        ->
SmsService

IPMS Report Generation

ReportGenerator
        ->
PdfReportGenerator
        ->
ExcelReportGenerator

Applying SOLID and Patterns Together

Controller

uses

Services

which depend upon

Interfaces

implemented by

Concrete Classes

Enterprise Architecture Example

Controller

Service

Repository

Database

Benefits of SOLID

  • Better Maintainability
  • Better Testing
  • Better Extensibility
  • Loose Coupling
  • Clean Architecture

Benefits of Design Patterns

  • Reusable Solutions
  • Consistent Architecture
  • Faster Development
  • Easier Maintenance

Mini Project

Build Student Placement Module.

Requirements:

  • Apply SRP
  • Apply DIP
  • Create Notification Factory
  • Create Configuration Singleton
  • Create Eligibility Strategy
  • Generate Reports

Best Practices

  • Follow SOLID Principles
  • Program to Interfaces
  • Favor Composition
  • Use Design Patterns Carefully
  • Keep Classes Focused
  • Minimize Coupling

Common Beginner Mistakes

Mistake Correct Approach
Large Classes Apply SRP
Direct Dependencies Apply DIP
Hardcoded Logic Use Strategy Pattern
Multiple Object Creation Use Factory
Global Variables Use Singleton Carefully

Practice Exercises

  1. Implement SRP.
  2. Implement OCP.
  3. Implement ISP.
  4. Implement DIP.
  5. Create Singleton Class.
  6. Create Factory Pattern.
  7. Create Builder Pattern.
  8. Create Strategy Pattern.
  9. Create Notification Module.
  10. Create Placement Eligibility Engine.

Chapter Summary

In this chapter, you learned:

  • SOLID Principles
  • SRP
  • OCP
  • LSP
  • ISP
  • DIP
  • Singleton Pattern
  • Factory Pattern
  • Builder Pattern
  • Strategy Pattern
  • Enterprise Application Design

In the next chapter, we will build the complete IPMS Capstone Project by applying all concepts learned throughout this tutorial.


Need help with your project?
I can help you explore our services or start an inquiry.