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

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

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

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

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
- Implement SRP.
- Implement OCP.
- Implement ISP.
- Implement DIP.
- Create Singleton Class.
- Create Factory Pattern.
- Create Builder Pattern.
- Create Strategy Pattern.
- Create Notification Module.
- 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.