SOLID principles

SOLID Principle is just acronym of five principles.
1 ) S — Single Responsibility Principle
2 ) O — Open/Closed Principle
3 ) L — Liskov’s Substitution Principle
4 ) I — Interface Segregation Principle
5 ) D — Dependency Inversion Principle

S — Single Responsibility Principle (SRP)

A class should have only a single responsibility and we only have one reason to change or modify it’s class. If we have another reason to change class then we need to split into different class.

public class Service {

public void insertStudent(Student student){
// insert student
}

public void updateStudent(Student student){
// update student
}

public void deleteStudent(Student student){
// delete student
}

public void insertCourse(Course course){
// insert course
}

public void updateCourse(Course course){
// update course
}

public void deleteCourse(Course course){
// delete course
}
}

the violation of SRP

In code above shows violation of SRP because Service.java handle the business logic for Student and Course class. In the future Service.java can become bloaters or even become our ‘nightmare’ because we put everything in Service.java.

The solution is we need to split Service.java into specific class to handle business logic for Student (StudentService.java) and Course (CourseService.java).

public class CourseService {

public void insert(Course course){
// insert course
}
public void update(Course course){
// update course
}
public void delete(Course course){
// delete course
}
}

...

public class StudentService {

public void insert(Student student){
// insert student
}
public void update(Student student){
// update student
}
public void delete(Student student){
// delete student
}
}

the compliance of SRP violation

O — Open/Closed Principle

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. It’s means the entity that we create should be extendable. By implementing this principle we are able to create a new feature/ behaviour without breaking the existing code.

public class Student {
private String type;

public void introduce() {
if ("highSchool".equals(type)) {
System.out.println("I am an high school student");
} else if ("underGraduate".equals(type)) {
System.out.println("I am a under graduate student");
} else {
System.out.println("I am a common student");
}
}
}

The violation of Open Closed Principles

The violation is when we need to add a new type of Student, we need to modify our code by adding a new codition. Let’s imagine that Student.java is already compiled and we use Student.java as library in our code, then until some day we need to add new type of Student. We can not do anything (or do everything in bad way) until the author of Student.java patch their code by adding a new condition.

For this case we can use inheritance to solve the problem.

public class Student {
public void introduce() {
System.out.println("I am a common student");
}
}
...
public class HighSchoolStudent extends Student {
@Override
public void introduce() {
System.out.println("I am an high school student");
}
}
...
public class UnderGraduateStudent extends Student {
@Override
public void introduce() {
System.out.println("I am a under graduate student");
}
}

The solution of violation

L — Liskov’s Substitution Principle (LSP)
Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.”.

Parent class should extendable by subclass without blowing up the software.

I — Interface Segregation Principle (ISP)
Many client-specific interfaces are better than one general-purpose interface. Here, the idea is split the ‘big’ interface to the smaller interface until client of the interface will only know about the methods that are related to them.

public interface Study {
void createPaper();
void createThesis();
}
...
public class Student implements Study {
public void createPaper() {
// create a paper
}
public void createThesis() {
throw new IllegalStateException("not implement yet");
}
}
...
public class UnderGraduateStudent extends Student {
@Override
public void createThesis() {
// create a thesis
}
}

The violation is implementation of Study interface in Student.java because by using Study interface in Student.java, Student.java forced to implement two methods; createPaper() and createThesis(). Actually, there is no logic for createThesis() in Student.java.

We need to split the general interface, in the case is Study interface, to more specific interface.

public interface PaperAble {
void createPaper();
}
...
public interface ThesisAble {
void createThesis();
}
...
public class Student implements PaperAble {
public void createPaper() {
// create a paper
}
}
...
public class UnderGraduateStudent extends Student implements ThesisAble {
public void createThesis() {
// create a thesis
}
}

D — Dependency Inversion Principle
Dependency Inversion is a great solution to reduce tight coupling in our software. Depend upon abstractions, not concretions.

“High-level modules should not depend on low level modules, rather both should depend on abstraction. Abstraction should not depend on details; rather detail should depend on abstraction.”

let’s straight to example :D

public class Main {
public static void main(String[] args) {
MySqlConnection connection = new MySqlConnection();
StudentRepository studentRepository = new StudentRepository(connection);
studentRepository.save();
studentRepository.delete();

TeacherRepository teacherRepository = new TeacherRepository(connection);
teacherRepository.save();
teacherRepository.update();
}
}
...
public class StudentRepository {
private MySqlConnection connection;
public StudentRepository(MySqlConnection connection){
this.connection = connection;
}
public void save() {
connection.insert();
}
public void delete() {
connection.delete();
}
}
...
public class TeacherRepository {
private MySqlConnection connection;
public TeacherRepository(MySqlConnection connection){
this.connection = connection;
}
public void save() {
connection.insert();
}
public void update() {
connection.update();
}
}

The violation is in repository class because that classes are depend on MySqlConnection.java to finish their method (insert, update, delete). Now, what happend if we need to change MySqlConnection.java to PsqlConnection.java ? We need modify all of classes that depend on MySqlConnection.java, it’s will be very dangerous because we need to modify a lot of class.

To solve this case, we can create an abstraction class that will implement in MySqlConnection.java and use that abstraction in our repository class.

public class Main {
public static void main(String[] args) {
// Connection connection = new MySqlConnection();
Connection connection = new PsqlConnection( );

StudentRepository studentRepository = new StudentRepository(connection);
studentRepository.save();
studentRepository.delete();

TeacherRepository teacherRepository = new TeacherRepository(connection);
teacherRepository.save();
teacherRepository.update();
}
}
...
public interface Connection {
void insert();
void update();
void delete();
}
...
public class MySqlConnection implements Connection {
public void insert() { }
public void update() { }
public void delete() { }
}
...

public class StudentRepository {
private Connection connection;
public StudentRepository(Connection connection) {
this.connection = connection;
}
public void save() {
this.connection.insert();
}
public void delete() {
this.connection.delete();
}
}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store