Design Principles [ S.O.L.I.D.]
-----------------------------------------------------------------
Single Responsibility Principle
-----------------------------------------------------------------
-----------------------------------------------------------------
The Single Responsibility Principle is a simple and intuitive principle. This is one of the 5 principles of S.O.L.I.D.. A responsibility in the current context is said to be a reason for change. The single responsibility principle states that if there more than one reasons for a class to change then we say that this class is not proper and it should be divided into further classes. There cannot be more than a reason for a class to be changed.
Example :
Suppose there is a class called "Customer" and contains a method called as "CalculateBills()" we should call this class has not been written properly. The customer class should only perform the customer related responsibilities.
Please see the below snap shot:
There are some observations out of the above snap shot:
- Customer class should be responsible for performing customer related responsibilities. For example : customer data validations, call to customer data access etc.
- It's doing some activity of Calculating bills (this is nowhere the responsibility of customer class to calculate bills)
- This also performs an another activity of logging the information to a text file.
What are the problems with the above class ?
- The customer class is doing things which this is not supposed to do
- At the change of logic in calculation , this class is required to be changed (Which is considered to be the second reason for the class to be changed)
- Its also logging error to the text file. What if the method of logging gets changed tomorrow. [for example : now the logging is to be done in DB or something like that.]. The class needs to be changed then (This is the third reason for the class to be changed)
We have seen that the above class is required to be changed for 3 reasons. First : when there are some changes in the customer related details, second : when there are changes in the logic of the bill calculation and third : when there is any change required for the logging mechanism of the error log. We can say that the above class is not following the SRP i.e. Single Responsibility Principles.
Some Of The Practical Examples Of S.R.P. Violation :
We could see the example of famous Swiss knife. Although its very useful but the problem in one of the knives leads to disturb the whole set. But if we can have each of those items separated its simple and easy to maintain. The one change will not affect the other ( See the below snapshots)
Re-Writing The Class In Order To Make It Follow S.R.P.:
There are couple of issues observed in the above "Customer" class. The biggest issue with the class which makes it violating the single responsibility is , there are more than one reasons for its changes.
- The above class contains CalculateBills() which is not related to customer. Someone can think for a separate class for this.
- The above class also contains a method to write into the test file. This is again not related to customer and quite changing in nature.
We can do the following and re-write the class in order to follow the Single Responsibility Principle :
We will try to overcome both of the above issues:
The above class contains CalculateBills() which is not related to customer. Someone can think for a separate class for this.
[Solution]
We are going to remove this method out from the customer class. We will write a separate class (may be "Bill" which will contain the method "CalculateBills()"
The above class also contains a method to write into the test file. This is again not related to customer and quite changing in nature.[Solution]
We are going to remove the method which only writes into text file. We may further write a class "Logger". This class logger will contain many methods for writing into files.
The new Customer Class looks like below :
New Logger class looks like :
And we are done !
-----------------------------------------------------------------
Open Closed Principle
-----------------------------------------------------------------
Open Closed Principle
-----------------------------------------------------------------
About
Software entities (classes, modules, functions) should be open for extension , but closed for modification. A software that is working fine should possibly not to be changed while introducing new functionality. Instead it can be extended.
Example
Let's take the above example under consideration and focus on the method SetCustomerStandardWorkingHours(int totalHours) method.
Let's see the method again in the below snap shot:
What does the above method do?
We are going to follow the below steps :
[Step 1]:
Write the class which contains a virtual method which can be overridden in any of the derived classes
[Step 2]:
As the different customers start coming , inherit this class and override the method for their specific type
[Step 3]:
Use the class in your application or main program.
Benefits of the above code implementation
-----------------------------------------------------------------
Liskov's Substitution Principle(L.S.P.)
-----------------------------------------------------------------
About
All the time while designing a program module we create some class hierarchies (Creating derived classes which for extending the base classes). We must make sure that the new derived class just extends without replacing the functionality of the base class otherwise the new derived class may produce some undesired effects when they are used in existing program.
Let's take the above example. Let's assume that the above class CustomerDP has two methods. SetCustomerStandardWorkingHours and UpdateDBWithHoursDetails. The method UpdateDBWithHoursDetails has been introduced later in the class.
Now a new customer called as "DiamondCustomer" can derive from the above class in order to introduce its functionalities. After the class has been derived and methods have been implemented, they can be used in the below ways:
So far everything looks good. Where is the L.S.P. in the above example. We have not discussed the L.S.P. yet. We are now going to derive the class CustomerDP and trying to override the methods in two ways. The one way is correct and the other is incorrect. The incorrect implementation in the below example will show the actual L.S.P.
Proper way the class Customer is being derived and methods get overridden
We see in the below implementation :
Incorrect way the class CustomerDP is being derived and methods get overridden
We see in the below implementation:
New Diamond Customer
And the Enquiry Class
Another example for L.S.P.:
And we are done !
-----------------------------------------------------------------
Interface Segregation Principle
-----------------------------------------------------------------
Thanks for reading.
Example
Let's take the above example under consideration and focus on the method SetCustomerStandardWorkingHours(int totalHours) method.
Let's see the method again in the below snap shot:
What does the above method do?
- Checks for the customer type
- Based on the type of the customer , it calculates the value of StandardWorkingHours
What is the problem with the above code?
- Look at the "if statement" . Calculation of standard working hours of the customer is based on the type of the customer. For example : if the customertype = 1 then it would be calculated as (TotalHours * 365 )/ 8
- What if .. . A new type of customer gets introduced. A new "if" block has to be introduced in order to introduce the new customer for calculating the working hours.
- We need to go to the “SetCustomerStandardWorkingHours” method and add an additional if which handles the new type of customer
- If we are changing the customer class again and again then we need to ensure that the previous conditions with the new one should be tested again
- In other words we are modifying the current customer code for every change and every time when we modify we need to make sure that all the previous functionalities are working fine as before
- We could have thought of extension rather than modifying the code again and again. This is called as Open (for extension) Closed (for modification) principle
We are going to follow the below steps :
[Step 1]:
Write the class which contains a virtual method which can be overridden in any of the derived classes
[Step 2]:
As the different customers start coming , inherit this class and override the method for their specific type
[Step 3]:
Use the class in your application or main program.
Benefits of the above code implementation
- Every time a new customer gets introduced there is no code changes required at the main CustomerDP class.
- We simply add a new Class. For example : SilverCustomer.
- This doesn’t require the previously existing classes / codes to be tested as it is a new class and doesn’t have to do with any existing ones.
And we are done !
-----------------------------------------------------------------
Liskov's Substitution Principle(L.S.P.)
-----------------------------------------------------------------
About
All the time while designing a program module we create some class hierarchies (Creating derived classes which for extending the base classes). We must make sure that the new derived class just extends without replacing the functionality of the base class otherwise the new derived class may produce some undesired effects when they are used in existing program.
Liskov’s principle states that if a program module is using a Base Class, then the reference of base class can be replaced with the derived class without affecting the functionalities
Now a new customer called as "DiamondCustomer" can derive from the above class in order to introduce its functionalities. After the class has been derived and methods have been implemented, they can be used in the below ways:
So far everything looks good. Where is the L.S.P. in the above example. We have not discussed the L.S.P. yet. We are now going to derive the class CustomerDP and trying to override the methods in two ways. The one way is correct and the other is incorrect. The incorrect implementation in the below example will show the actual L.S.P.
Proper way the class Customer is being derived and methods get overridden
We see in the below implementation :
- DiamonCustomer class doesn't change the meaning of SetCustomerStatndardWorkingHours method. It does the same calculation for the diamond customer.
Incorrect way the class CustomerDP is being derived and methods get overridden
We see in the below implementation:
- EnquiryEntity1 is the class which derives from CustomerDP
- Look at the implementation of the overriding methods. They are completely going to change the meaning of the methods.
- In other words we may say that its completely replacing the functionalities of its base class. Hence it violates the L.S.P.
Solution
Let's follow the below steps to find out the solution :
Customer Class implementing the interfaces :Let's follow the below steps to find out the solution :
- Create different interfaces containing the different concerns. Here the two methods can be taken in two different interfaces
- For example : let's have the interfaces “IStandardTimeCalculation” and “IStandandardTimeToDB”
- The Customer class may now implement both the interfaces where as the EnquiryEntity may implement the IStandardTimeToDB
Snap shot for your reference :
The two interfaces :
New Diamond Customer
And the Enquiry Class
Another example for L.S.P.:
And we are done !
-----------------------------------------------------------------
Interface Segregation Principle
-----------------------------------------------------------------
About :
Interface Segregation Principle states that the clients should not be forced to implement interfaces they don’t use. Its like – instead of one fat interface many small interfaces can be preferred based on groups of methods each serving.
Understanding The Problem By Previous Example :
- Assume that our customer class has become popular and is being used by hundreds of happy clients
- Just to remind we had two interfaces IStandardTimeCalculation & IStandandardTimeToDB
- As the new clients getting added, a new client has come up with the requirement to read standard time value from DB. [the interface IStandardTimeToDB is only meant for writing into DB]
- So developers without thinking may go and add a new method to the Interface (IStandardTimeToDB). Let say that the newly added method is “ReadHoursDetailsFromDB”
- The effect of this small change is going to be huge. This will lead & force all the clients using the previous interface to have this method implemented unnecessarily
- The new requirement has two kinds of clients
- Those who want just to Update Hours Details
- Those who want to Update + Read Hours Details
- [By changing the existing interface we are doing an awful thing & disturbing the hundreds of satisfied clients]
A Better Approach To Solve The Problem
The better approach is to keep the existing clients in their own sweet world and the new clients need to be served separately. For this purpose we may create a new interface which would contain the read method and implement this for newer clients.
See the snap shot below :
And we are done !
About
Continue...-----------------------------------------------------------------
Dependency Inversion Principle
-----------------------------------------------------------------
About
Thanks for reading.
Comments
Post a Comment