Wednesday 27 August 2014

Single Responsibility Principle

According to the single responsibility principle:
A class,a method ,an assembly should have one and only one reason to change.

Explanation:


  • If we have more than one reasons ,say you have n reasons to change for a class, we have to split the functionality in into n number classes.
  • Each class will handle only one responsibility and on future if we need to make one change we are going to make it in the class which handle it. 
  • When we need to make a change in a class having more responsibilities the change might affect the other functionality of the classes.
  • The Single Responsibility Principle represents a good way of identifying classes during the design phase of an application and it reminds you to think of all the ways a class can evolve.
  • A good separation of responsibilities is done only when the full picture of how the application should work is well understand.

Example

Suppose I have a project for customer management , using which users can
a. Do CRUD(Create Retrieve Update Delete) operations on customer data
b. Send mails for CU to customer and D to Administrator
c. and also, we have a requirement to log exceptions if there is a failure.
So, the first step we do is create three layers in the CustomerManagementProject:
a. UI
b. BAL
c. DAL
Now, UI takes care of all UI related functionality and DAL takes care of all data related functionality.
The middle tier has the business rules to
a. Create/Update/Delete Customers
b. Sending email and email format
c. Log Exceptions.
The BAL class looks like:
The sample sequence diagram is:
Now,
if there is a change in the business rules to send email or log exceptions we are going to touch the manage customerBAL class.
So, this class is violating SRP.

How To Resolve:


1. Although BAL has to do all the three functions of managing customers, sending mails and logging errors.
Let us have three separate projects:
a. ManageCustomerBAL
b.Exceptions
c.Email

So, now my solution looks something like:
Even though we have moved exception and email to two different projects, but still then we need to create an object of the exception class and log exceptions.
For example my BAL refers to Exception like

Add reference
Create an instance of the class
Call the method
So, now the sequence diagram looks like:
Similarly to log email exceptions we have another class in LogException namespace.
But suppose, the requirement changes and I need to add the exception to event viewer as well what do I do?

You cannot come again and instance of another class in ManageCustomerBAL.
If you create it you are again violating SRP.

So, what should I do??

Now , we need to add an interface for logging. The exception class and the BAL refer to the exception logging methods using interface.
So,What we need to do is replace the FileException Class with a generic interface and extend the FileException class from this interface.
Step 1: Create a project to contain the Interface.
Step 2: And add method to the interface.


Step 4 : Extend this Interface in all the exception classes

Step 5: Remove the reference to Exception from BAL and add reference to IInterface.
Step 6: Add reference for the interface in BAL





Now that we have added an interface , there is going to be no change in the BAL if we are going to add a new class to the LogException Namespace.
The problem is how do I create an object for the interface?
So, I should use a factory class.
Step 7: Add a ExceptionFactory project 
Step 8 : Add reference to Exception and IInterface to the ExceptionFactory project.
The interface is what which will help to identify the classes properly.
and how do you identify the class?
Step 9:You have a key-value pair in the web.config file something like

Step 10: In the ExceptionFactory add a  method which reads this web.config and creates objects of required classes.

Step 11: Refer factory class in BAL
So, whenever you have a change in requirement you need to change only at two places:
a. The ExceptionFactory
b.The LogException class.

No comments :