Mayur Lohite Published a new article on Web, Mobile & Software Dev, Mobile Development, Web Development
14-Sep-2019
At first, interfaces came into focus because there was no multiple inheritance supported by C#, meaning you could not inherit from multiple classes, but you could implement multiple interfaces. The interfaces are grouping of object in terms of behavior.
An interface contains only signatures. There is no implementation, only the signatures of the functionality the interface provides. An interface can contain signatures of methods, properties, indexers & events.
Interface doesn't do anything like classes and abstract
classes, it just defines what the class will perform if some class inherits it. An interface can also be inherited from another interface.
If we take an example of USB (Universal Serial Bus), it's an interface which has signature of Connection functionality. The USB interface only knows I have to connect with Desktop Computer or laptop or anything, but it does not know what implementation will come to connection. It may be Pen drive (mass storage), it may be Printer(COM Ports).
Let's see the concept in a programmatic way.
public interface IUSB { public void MakeConnection(); }
public class Pendrive: IUSB { public void MakeConnection() { //The code for connecting pen drive to desktop, laptop or other throw new NotImplementedException(); } }
public class Printer: IUSB { public void MakeConnection() { //The code for connecting printer to desktop, laptop or other throw new NotImplementedException(); } }
Now the decoupled system means the way of defining the architecture of project that one module cannot depend on another module. The system should depend on abstraction rather than implementation.
In a realistic way, suppose I am currently designing the MVC project with Microsoft SQL Server but if in future I have to change the database to MySQL. In this case, I just need to change the Repository Implementation not a Controller.
So my Controller should be implementing the abstraction/interfaces of Repository. When I change the implementation of Repository, I just have to change it to new implementation, rest nothing will be changed.
private readonly IRepository _repository; public ActionResult Index() { _repository = new MSSQLRepository(); //or //_repository = new MySQLRepository(); }
As I am a developer, I got one requirement from client. The requirement is that I have to get current exchange rate by currency. So I have to Pass USD and Get current INR Rate or Current EURO rate. There are various web services that offer this functionality.
So consider providers ABC, DEF & PQR provide these web services, but they charge different rates. So my client said to me at first we will try ABC's Service, but if we find it's not reliable, then we have to change it at a later stage.
So let's consider the dirty code first:
public class ProductController : Controller { public async Task<ActionResult> DisplayProduct() { Product p = new Product(); p.Name = "Test Product"; p.Type = "USD"; p.Price = 5; //All ABC Service code which returns USD to INR double INR = <RETURN FROM WEB SERVICE> p.Price = p.Price * INR; return View(p); } }
Now let's assume that I am going to use this dirty code implementation directly in the controller. It has some disadvantages.
Now, I have to design some logic in a decoupled way, So when client says we have to go with another service provider, I don't have to change much in my Controller. But the problem is how to design the decoupled logic and then Interface comes in focus.
The design is as follows:
ICurrencyExchangeService
Interface.GetCurrentINR(string currency);
GetCurrentEURO(string currency);
public interface ICurrencyExchangeService { double GetCurrentINR(string type); double GetCurrentEURO(string type); }
ABCCurrencyExchangeService
class which inherited from ICurrencyExchangeService
public class ABCCurrencyExchangeService : ICurrencyExchangeService { public double GetCurrentINR(string type) { double exchangeRate = 0.0; //Call the ABC web service with appropriate parameters as per the documentation. //Assign converted rate to exchangeRate variable return exchangeRate; } public double GetCurrentEURO(string type) { double exchangeRate = 0.0; //Call the ABC web service with appropriate parameters as per the documentation. //Assign converted rate to exchangeRate variable return exchangeRate; } }
ICurrencyExchangeService
in my Controller
.public class ProductController : Controller { ICurrencyExchangeService _currencyService = new ABCCurrencyExchangeService(); public async Task<ActionResult> DisplayProduct() { Product p = new Product(); p.Name = "Test Product"; p.Type = "USD"; p.Price = 5; //But we have to show INR prices double INR = _currencyService.GetCurrentINR(p.Type); p.Price = p.Price * INR; return View(p); } }
ABCCurrencyExchangeService
Class implementation as per the DEF Service documentation. But it's against the name standard because we are implementing the DEF service under the class name ABCCurrencyExchangeService
.DEFCurrencyExchangeService
which inherited from ICurrencyExchangeService Interface
and I implement all the methods as per the DEF Service.public class DEFCurrencyExchangeService : ICurrencyExchangeService { public double GetCurrentINR(string type) { double exchangeRate = 0.0; //Call the DEF web service with appropriate parameters as per the documentation. //Assign converted rate to exchangeRate variable return exchangeRate; } public double GetCurrentEURO(string type) { double exchangeRate = 0.0; //Call the DEF web service with appropriate parameters as per the documentation. //Assign converted rate to exchangeRate variable return exchangeRate; } }
DEFCurrencyExchangeService Class
. So my new Product Controller looks like:public class ProductController : Controller { //ICurrencyExchangeService _currencyService = new ABCCurrencyExchangeService(); ICurrencyExchangeService _currencyService = new DEFCurrencyExchangeService(); public async Task<ActionResult> DisplayProduct() { Product p = new Product(); p.Name = "Test Product"; p.Type = "USD"; p.Price = 5; //But we have to show INR prices double INR = _currencyService.GetCurrentINR(p.Type); p.Price = p.Price * INR; return View(p); } }
If you don't know about DI or how to use it, please check the following links:
public static class UnityConfig { public static void RegisterComponents() { var container = new UnityContainer(); // register all your components with the container here // it is NOT necessary to register your controllers // e.g. container.RegisterType<ITestService, TestService>(); //container.RegisterType<ICurrencyExchangeService , ABCCurrencyExchangeService>(); container.RegisterType<ICurrencyExchangeService , DEFCurrencyExchangeService >(); DependencyResolver.SetResolver(new UnityDependencyResolver(container)); } }
ICurrencyExchangeService Interface
was pointing to ABCCurrencyExchangeService Class
and now it's pointing to DEFCurrencyExchangeService Class
. The dynamic object creation is done by UNITY DI.ProductController Class:
public class ProductController : Controller { private readonly ICurrencyExchangeService _currencyService; public ProductController(ICurrencyExchangeService currencyService) { _currencyService = currencyService; } public async Task<ActionResult> DisplayProduct() { Product p = new Product(); p.Name = "Test Product"; p.Type = "USD"; p.Price = 5; //But we have to show INR prices double INR = _currencyService.GetCurrentINR(p.Type); p.Price = p.Price * INR; return View(p); } }