SOLID Design Principles simplified with UML

Rikam Palkar
Level Up Coding
Published in
5 min readMay 9, 2020

--

Let’s learn SOLID principles with one big example. This is the most common interview question as well.
First, we need to break down the abbreviation.

S. Single Responsibility Principle

O. Open Closed Principle

L. Liskov’s Substitution Principle

I. Interface Segregation Principle

D. Dependency Inversion Principle

Pretty cool huh? let’s explore each of them.

1.Single Responsibility Principle: A class must have a specific responsibility and nothing else. It should change for only one reason.
So the responsibility is actually encapsulated within the class, saying our class HAS-A Responsibility.

As you can see in this UML: class IPhone has properties that can define an IPhone. But hold on what is CalculateTotal_Sale() doing here?

Do you see the problem? It is not a responsibility of an IPhone class to calculate the Total sale

Problem: what if tomorrow I have IPad class, I’ll have to re-code the same method for that class as well.

Solution: Rather we can move the responsibility of calculating Total sale to the new class Sale. And an IPhone can encapsulate Sale to calculate its total sale.

Here, now a Sale is managing the responsibility of calculating TotalSale(). And our IPhone class simply reuse this responsibility rather than creating one by himself. Hence IPhone has the TotalSale().

2.Open-Closed principle: Open for Extension, Closed for Modification. Software entities (objects, modules, functions) should be open for extension, but closed for modification. This simply means that an entities should be easily extendable without modifying them-self.

Problem: We know that different IPhone models have different specs, right? IPhone XR has different specifications than IPhone X.

Solution: We must abstract our problem so that our IPhone class can delegate its implementation based on model type.

Now IPhone can ask for specific Model and set specifications based on model it gets.

Here class IPhone is closed for modification but it is open for extension. Note that class IPhone now has an IModel encapsulated. So ModelName property is not responsibility of IPhone class anymore. Yet again we are using our first design principle(Single responsibility). And our abstraction is generic enough to satisfy any model apple ever creates.

Our client: an IPhone doesn't have to change just because Apple decides to have new Model (closed for modification). And apple can now have “n” number of models (open for extension).

3. Liskov’s Substitution Principle: parent classes should be easily substituted with their child classes.

In our UML above as we can see that, we have created IModel interface, now any class which inherits the IModel must define all of it’s methods in order to satisfy IS-A relationship else you’ll get compile time error. But your compiler is not going to be there when you inherit classes rather than interfaces.

IPhone HAS-A CPU class, IPhone could have Bionic chips but none of the IPhone is compatible with Snapdragon.

Problem: Have you ever seen IPhone with Snapdragon? Hell No!!!, Right?

So when we try to assemble Snapdragon’s CPU to our IPhone class it will throw an error as you can see in Snapdragon865 class it is throwing not implemented exception. Because IPhone X & XR are only compatible with Bionic chips.

Solution: We should not have child classes which are not completely implementing their parent’s behavior.

Instead of Snapdragon, Apple has A8, used in IPhone 6. Hence it is compatible with an Iphone.

4. Interface Segregation Principle: Remember Single responsibility principle? It is the same principle but this principle is applied on interfaces instead.

Problem: We should not have a more generalized interface. i.e. we must avoid jumbling up everything in one single interface then forcing their concrete classes to define those methods that they might not require and they end up in throwing a NotImplementedException.

Instead, we must have many client-specific interfaces than one general interface.

We have 2 IPhones XR & X: Iphone XR has single camera where IPhone X has dual camera. So it would be wrong for an IPhoneXR to define DualCamera, as it does not have a dual camera. Here IPhone XR is only defining Single camera, DualCamera is throwing an exception.

Solution: As discussed, we should not have a generalized interface. We can have top level abstraction but implementation has to be broken down into small pieces as per their requirements.

Here class IPhone can set up camera based on their model.

class IPhone has a camera which could be Single-Dual camera based on Model type. for XR it is single camera setup & for X it is a dual camera setup.

5. Dependency Inversion Principle: Our application must be loosely coupled. classes should depend on abstraction but not on concretion. Because tightly coupled applications gets more tangled with each other as application grows.

Problem: We have tight coupling between IOSUpdate & IPhone. So if tomorrow Apple needs an IOS update for IPad, then we will have to make one more tight coupling relationship, And it gets difficult to maintain as Application grows more.

IOSUpdate is tightly coupled with IPhone.

Solution: An abstraction. Rather than directly communicating with concrete class there should be loose coupled class.

IUpdate: Abstraction. IPhoneUpdate & IPadUpdate are concrete classes of an abstraction.

As you can see above IUpdate is an interface which has 2 concrete classes IPhoneUpdate & IPadUpdate. And when our client which is IPhone in this case ask for an update we can simply inject IPhoneUpdate dependency in constructor or method.

For an IPad, It is injecting IPadUpdate dependency.

So in future, when Apple needs to have a new product say MacBook ,we can simply create one more MacBookUpdate class which will be an concrete representation of IUpdate interface. And client MacBook can resolve <IUpdate, MacBookUpdate> dependency.

Dependency inversion is a wide topic to learn in itself.

I have covered that in my other blog, feel free to visit if you wish to understand its working:

Connect with me:

https://github.com/RikamPalkar

https://www.linkedin.com/in/rikampalkar/

https://www.c-sharpcorner.com/members/rikam-palkar

https://twitter.com/rikam_cz

--

--