What are SOLID PRINCIPLES ?

kaankubat
7 min readFeb 5, 2022

--

With examples in this article, we will easily understand SOLID Principles.

Let’s briefly introduce solid for those who have never heard of it before.

The Software Engineering sector is growing day by day and the codes written in this sector can be in many different structures. It is getting harder to read, understand and develop these different structures. At this point, SOLID Principles are literally there to make the life of Software developers easier. Object-Oriented Programming is the basis of SOLİD Principles, which enables us to increase readability and create flexible code structures.

I think we are starting to understand the SOLID Principles, so let’s elaborate on SOLID a little more.

As you can see in the image, SOLID takes its name from the first letter of its principles and knowing the details of these principles is very important for the software developer.

1. Single Responsibility Principle

According to Single Responsibility principles, when developing software, each class or method should have a single responsibility. Too much work should never be done.
“Do one thing and make the best of it.” can be said for this principle. By complying with this principle, the events that will cause difficulties for the team, the company, and the software developer are minimized after the changes made in the project.

In the first example, the Single Responsibility principle was violated because Update and Insert were written together under a method. In addition to the error that will occur when we call the method, readability and flexible are reduced. Changes to be made in the code in the future have been complicated.

In the second example, since Update and Insert were written under different methods, the Responsibility principle was applied. The risk of error that will occur when we call the method has been eliminated. Readability and flexibility have increased. Changes to be made in the code in the future have been simplified.

2. Open/Close Principle

According to the Open/Close principle, projects should be open to adding new features and closed to changing their features. That is, when you add a new feature to the project, you should not change the code you wrote before. To give an example from daily life, the car has 4 wheels and 1 steering wheel. The car object is not subject to change, we cannot make the of 3 wheels , but we can improve the car by adding a stereo.

If one more Invoice Type comes then we need to add another else if condition within the source code of the above GetInvoiceDiscount() method which violates the Open closed principle.

If we want to show one more example.

Let’s we want to add a new feature to the application .

The programmer who does not know or care about the Open/Close principle will add new features as in the example or in a way similar to the example. Adding if else loops to the CustomerDal class pollutes the code and makes it difficult to control.

Well, let’s see how the conscious programmer reading this article innovates the project and applies the Toggle principle.

  1. Developer should abstract the CustomerDal class with the ICustomerDal class.
  2. Care should be taken when using enum classes. Is it necessary to use an enum class, it should be analyzed well.
  3. Add operation should be write with ICustomerDal.
  4. The innovations to be added to the project should be classified separately, for example: SqlCustomerDal, JpaCustomerDal, HibernateCustomerDal.

3. Liskov Substitution Principle

According to the LSP, “Derived classes must be substitutable for base classes.” Make sure that new derived classes are extending the base classes without changing their behaviour. As I have shown in the other principles, we will see the code that is against this principle and the restructuring of this code in accordance with the Liskov principle.

The LSP is popularly explained using the square and rectangle example. if we assume an ISA relationship between Square and Rectangle. Thus, we call “Square is a Rectangle.” The code below represents the relationship.

Above is the code for Square. Note that Square extends Rectangle.

In this case, we try to establish an ISA relationship between Square and Rectangle such that calling “Square is a Rectangle” in the below code would start behaving unexpectedly if an instance of Square is passed. An assertion error will be thrown in the case of checking for “Area” and checking for “Breadth,” although the program will terminate as the assertion error is thrown due to the failure of the Area check.

The class demonstrates the Liskov Substitution Principle (LSP) As per the principle, the functions that use references to the base classes must be able to use objects of derived class without knowing it.

Thus, in the example shown below, the function calculateArea which uses the reference of “Rectangle” should be able to use the objects of derived class such as Square and fulfill the requirement posed by Rectangle definition. One should note that as per the definition of Rectangle, following must always hold true given the data below:

  1. Length must always be equal to the length passed as the input to method, setLength
  2. Breadth must always be equal to the breadth passed as input to method, setBreadth
  3. Area must always be equal to product of length and breadth

In case, we try to establish ISA relationship between Square and Rectangle such that we call “Square is a Rectangle”, above code would start behaving unexpectedly if an instance of Square is passed Assertion error will be thrown in case of check for area and check for breadth, although the program will terminate as the assertion error is thrown due to failure of Area check.

The Square class does not need methods like setBreadth or setLength. The LSPDemo class would need to know the details of derived classes of Rectangle (such as Square) to code appropriately to avoid throwing error. The change in the existing code breaks the open-closed principle in the first place.

4. Interface Segregation Principle

The Interface Segregation Principle (ISP) states that clients should not be forced to depend upon interface members they do not use. When we have non-cohesive interfaces, the ISP guides us to create multiple, smaller, cohesive interfaces.

When you apply ISP, classes and their dependencies communicate using tightly-focused interfaces, minimizing dependencies on unused members and reducing coupling accordingly. Smaller interfaces are easier to implement, improving flexibility and the possibility of reuse. As fewer classes share these interfaces, the number of changes that are required in response to an interface modification is lowered, which increases robustness.

ı

In this scenario, there are Company employees and Company employees assigned from other companies. While Company Workers are Override with Pay, Food, Work, Out Source Workers are required to be override only with Pay, Work.

The biggest mistake made here is to leave the Food method under the OutSourceWorker empty or return null.

This wrong approach can be solved correctly as follows.

5.Dependency Inversion Principle

“High-level modules should not depend on low-level modules. Both should depend on abstractions.”

“Abstractions should not depend on details. Details should depend on abstractions.”

According to this principle, abstract and interface classes should be eliminated, since concrete classes are subject to frequent changes. Secondly, abstractions should not depend upon details; details should depend upon abstractions. The idea is that we isolate our class behind a boundary formed by the abstractions it depends on.

Examining the above code, it is seen that the ExceptionReporter class (high-level class) is directly dependent on the OracleDatabase class (low-level class). Unfortunately, if you want to use MySQL instead of Oracle as a database in the future, you will have to intervene in this class. This is undesirable behavior. The solution to this is to abstract the dependencies here.

Here, the software developer should handle the issue like this.

As can be seen in the code, the high-level class does not directly connect to the subclass, but through abstractions. With a new implementation here, the superclass is prevented from being directly affected.

Thank you for reading, in this article I tried to tell you what I know, what I learned and what I researched, I hope it will be useful.

--

--