SOLID principles are at the core of software engineering practices.
For the quick revision I have been
using ChatGPT to get the relevant examples for each of the principle. I have compiled below my
search results for SRP and OCP for quick lookup.
SRP
The Single Responsibility Principle (SRP) in software engineering states that a class or module should
have only one reason to change. Violating this principle often leads to code that is harder to maintain
and understand. Here's an example of a class that violates the SRP:
SRP Violation:
In this example, we have a ReportGenerator class that both generates a report and sends it via email,
violating the SRP.
public class ReportGenerator {
public String generateReport(Employee employee) {
// Generate a report for the employee
String report = "Employee Report for " + employee.getName() + ": ...";
return report;
public void sendReportByEmail(String report, String email) {
// Code to send the report via email
System.out.println("Sending report to " + email + ": " + report);
public class Employee {
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
In this code, the ReportGenerator class has two responsibilities: generating the report and sending it
via email. If any changes are needed in either report generation or email sending logic, this class
would have multiple reasons to change, which violates SRP.
SRP Adherence:
To adhere to SRP, we'll separate the responsibilities into two classes: ReportGenerator and
EmailSender.
public class ReportGenerator {
public String generateReport(Employee employee) {
// Generate a report for the employee
String report = "Employee Report for " + employee.getName() + ": ...";
return report;
public class EmailSender {
public void sendReportByEmail(String report, String email) {
// Code to send the report via email
System.out.println("Sending report to " + email + ": " + report);
}
Now, the ReportGenerator class is responsible only for generating reports, and the EmailSender class
is responsible solely for sending emails. This separation of concerns adheres to the SRP, making the
code more maintainable and easier to understand. If changes are needed in one responsibility (e.g.,
report generation), it won't affect the other (e.g., email sending).
OCP
*The Open-Closed Principle (OCP) states that software entities (e.g., classes, modules, functions)
should be open for extension but closed for modification. Violating the OCP can lead to code that is
brittle and difficult to maintain when new functionality is added. Here's an example in Java that
violates the OCP and how it can be refactored to adhere to the *principle
OCP Violation:
Consider a simple Shape hierarchy with two types: Circle and Rectangle. We have a GraphicEditor
class that calculates and returns the area of each shape.
class Shape {
public enum Type { CIRCLE, RECTANGLE }
private Type type;
public Shape(Type type) {
this.type = type;
public double calculateArea() {
if (type == Type.CIRCLE) {
// Calculate and return the area of a circle
return Math.PI * Math.pow(5, 2); // Radius is hard-coded here
} else if (type == Type.RECTANGLE) {
// Calculate and return the area of a rectangle
return 10 * 20; // Length and width are hard-coded here
return 0;
}
class GraphicEditor {
public double computeShapeArea(Shape shape) {
return shape.calculateArea();
In this code, the GraphicEditor class calculates the area of shapes, but the calculation logic is hard-
coded for both circles and rectangles. If you need to add more shapes or change the area calculation
for existing shapes, you would need to modify the Shape class, violating the OCP.
OCP Adherence:
To adhere to the OCP, we can use a strategy pattern to make the code open for extension and closed
for modification. We'll create a separate interface for area calculation and implement it for each
shape type.
interface AreaCalculator {
double calculateArea();
class Circle implements AreaCalculator {
private double radius;
public Circle(double radius) {
this.radius = radius;
@Override
public double calculateArea() {
return Math.PI * Math.pow(radius, 2);
class Rectangle implements AreaCalculator {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
@Override
public double calculateArea() {
return length * width;
class GraphicEditor {
public double computeShapeArea(AreaCalculator shape) {
return shape.calculateArea();
In this refactored code, we have introduced the AreaCalculator interface. Each shape (e.g., Circle and
Rectangle) implements this interface with its own area calculation logic. The GraphicEditor class now
accepts objects that implement AreaCalculator, making it open for extension. If you want to add new
shapes, you can create new classes that implement AreaCalculator without modifying existing code,
adhering to the OCP.