Interface segregation principle (ISP) in C-Sharp

According to Robert Martin, no client should be forced to depend on methods it does not use.

To understand ISP lets move back to Customer example again of previous article.

Suppose we have two teams in the bank one just for account opening and other is for account opening and credit card sales. Our old model of customer as explained in previous article Liskov substitution principle (LSP), was suitable for Account opening team (Sales Team). So What we will need to do for Credit Card team (Credit Card Sales Team), They wants to view customer balances in their bank accounts, as well as opening bank account too for new credit card customer. To overcome this problem every developer will look for adding one more new method ReadCutomerBalance for interface INewCustomer as follows.

public interface INewCustomers { void AddCustomer(); decimal ReadCutomerBalance(); }

By adding new method ReadCutomerBalance in Interface INewCustomers, we might to implement ReadCutomerBalance for each and every old classes Customer, CoorporativeCustomer and SeniorCustomer as follows.

using System; namespace SOLID { public static class ErrorLogger { public static void ErrorHandler(string error) { System.IO.File.WriteAllText(@"c:\Error.txt", error); } } public interface INewCustomers { void AddCustomer(); decimal ReadCutomerBalance(); } public interface IInterest { double getInterest(double CurrentAmt); } public class Customer : INewCustomers, IInterest { public virtual void AddCustomer() { try { // Business logic and database logic goes here. } catch (Exception ex) { ErrorLogger.ErrorHandler(ex.ToString()); } } public virtual decimal ReadCutomerBalance() { return 1; } public virtual double getInterest(double CurrentAmt) { return (CurrentAmt * 3) / 100; } } public class CoorporativeCustomer : Customer { public override void AddCustomer() { try { // Business logic and database logic goes here. } catch (Exception ex) { ErrorLogger.ErrorHandler(ex.ToString()); } } public override decimal ReadCutomerBalance() { return 1; } public override double getInterest(double CurrentAmt) { return (CurrentAmt * 3.5) / 100; } } public class SeniorCustomer : CoorporativeCustomer { public override void AddCustomer() { try { // Business logic and database logic goes here. } catch (Exception ex) { ErrorLogger.ErrorHandler(ex.ToString()); } } public override decimal ReadCutomerBalance() { return 1; } public override double getInterest(double CurrentAmt) { return (CurrentAmt * 4.5) / 100; } } public class GuestCustomer : IInterest { public double getInterest(double CurrentAmt) { return (CurrentAmt * 5) / 100; } } }

Problem:
By adding new method ReadCustomerBalance in Interface INewCustomers, we must to implement ReadCustomerBalance for each and every old class. Which allows right to Sales team to get any customer account balances. which will break the bank rule. Sales team will becomes Credit Card Team. Moreover, again testing each and every methods for old happy sales team.

Solution:
According to Interface segregation principle (ISP), Clients should not be enforce to implement those interfaces, that they need not to use or depends.

So the better approach would be to create a new interface ICCCustomers with new ReadCustomerBalance method implemented by INewCustomers, rather than modifying the old interface INewCustomers. Now create a new class for CreditCardCustomers inherit from ICCCustomers as follows.

public interface INewCustomers { void AddCustomer(); } public interface IInterest { double getInterest(double CurrentAmt); } public interface ICCCustomers: INewCustomers { decimal ReadCustomerBalance(); }

Now we have flexibility for both the teams Account opening as well as Credit Card. We will implement Account opening team class Customer from interfaces INewCustomers, IInterest for adding new customer and getting interest details respectively, Credit Card team CreditCardCustomers from interfaces INewCustomers, IInterest and ICCCustomers for adding new customer, getting interest details and account balance respectively as shown below in complete example.

using System; namespace SOLID { public static class ErrorLogger { public static void ErrorHandler(string error) { System.IO.File.WriteAllText(@"c:\Error.txt", error); } } public interface INewCustomers { void AddCustomer(); } public interface IInterest { double getInterest(double CurrentAmt); } public interface ICCCustomers: INewCustomers { decimal ReadCustomerBalance(); } public class Customer : INewCustomers, IInterest { public virtual void AddCustomer() { try { // Business logic and database logic goes here. } catch (Exception ex) { ErrorLogger.ErrorHandler(ex.ToString()); } } public virtual double getInterest(double CurrentAmt) { return (CurrentAmt * 3) / 100; } } public class CoorporativeCustomer : Customer { public override void AddCustomer() { try { // Business logic and database logic goes here. } catch (Exception ex) { ErrorLogger.ErrorHandler(ex.ToString()); } } public override double getInterest(double CurrentAmt) { return (CurrentAmt * 3.5) / 100; } } public class SeniorCustomer : CoorporativeCustomer { public override void AddCustomer() { try { // Business logic and database logic goes here. } catch (Exception ex) { ErrorLogger.ErrorHandler(ex.ToString()); } } public override double getInterest(double CurrentAmt) { return (CurrentAmt * 4.5) / 100; } } public class CreditCardCustomers : INewCustomers, ICCCustomers, IInterest { public virtual void AddCustomer() { try { // Business logic and database logic goes here. } catch (Exception ex) { ErrorLogger.ErrorHandler(ex.ToString()); } } public virtual decimal ReadCustomerBalance() { return 1; } public virtual double getInterest(double CurrentAmt) { return (CurrentAmt * 4.5) / 100; } } public class GuestCustomer : IInterest { public double getInterest(double CurrentAmt) { return (CurrentAmt * 5) / 100; } } public class Program { static void Main(string[] args) { INewCustomers c = new Customer(); c.AddCustomer(); // Not Allowed //c.ReadCustomerBalance(); ICCCustomers cc = new CreditCardCustomers(); cc.AddCustomer(); cc.ReadCustomerBalance(); } } }

In next article we will learn Dependency Inversion Principle (DIP) i.e. D of SOLID Design and Pattern

If you have any query or question or topic on which, we might have to write an article for your interest or any kind of suggestion regarding this post, Just feel free to write us, by hit add comment button below or contact via Contact Us form.


Your feedback and suggestions will be highly appreciated. Also try to leave comments from your valid verified email account, so that we can respond you quickly.

 
 

{{c.Content}}

Comment By: {{c.Author}}  On:   {{c.CreatedDate|date:'dd/MM/yyyy'}} / Reply


Categories