An Interface
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.
Using the Code
An USB Interface
public interface IUSB
{
public void MakeConnection();
}
The Pendrive Class
public class Pendrive: IUSB
{
public void MakeConnection()
{
throw new NotImplementedException();
}
}
The Printer Class
public class Printer: IUSB
{
public void MakeConnection()
{
throw new NotImplementedException();
}
}
Decoupled System
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();
}
Decoupled System Using Interface By Realistic Example
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;
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.
- If I implement service code directly to controller, I have to change it in all controllers which need currency conversion functionality. For this demo, I have only 1 Controller and 1 Action, but in a real world application, we may have lots of Controllers and Actions.
- To change the code in each and very controller which needs conversion functionality, it's very frustrating, and it's the opposite of Good Programming Standard. As per Programming Standard, we have to reduce repetitive efforts.
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:
- What is important here is, I have to get current exchange rate by passing currency.
- So I created one
ICurrencyExchangeService
Interface.
- Then, I just defined the function signatures in interface, e.g.,
GetCurrentINR(string currency);
GetCurrentEURO(string currency);
ICurrencyExchangeService Interface
public interface ICurrencyExchangeService
{
double GetCurrentINR(string type);
double GetCurrentEURO(string type);
}
- Now I created
ABCCurrencyExchangeService
class which inherited from ICurrencyExchangeService
- All functions [defined in interface] will be implemented here as per the ABC Service documentation
ABCCurrencyExchangeService Class
public class ABCCurrencyExchangeService : ICurrencyExchangeService
{
public double GetCurrentINR(string type)
{
double exchangeRate = 0.0;
return exchangeRate;
}
public double GetCurrentEURO(string type)
{
double exchangeRate = 0.0;
return exchangeRate;
}
}
- Now I am using
ICurrencyExchangeService
in my Controller
.
ProductController Controller [MVC]
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;
double INR = _currencyService.GetCurrentINR(p.Type);
p.Price = p.Price * INR;
return View(p);
}
}
- All my code is going well but after few days, client says the service is not reliable. We have to migrate it to another service, i.e., DEF Service.
- Now what to do? I have 2 options:
- Change the
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
.
- Also one more disadvantage is suppose after some days, if client says we have to revert our old service that is ABC, then we have to again implement ABC service.
- The second and good option is we will create new class
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;
return exchangeRate;
}
public double GetCurrentEURO(string type)
{
double exchangeRate = 0.0;
return exchangeRate;
}
}
- Now I just have to change the one line in my controller. The repository is now pointing to
DEFCurrencyExchangeService Class
. So my new Product Controller looks like:
public class ProductController : Controller
{
ICurrencyExchangeService _currencyService = new DEFCurrencyExchangeService();
public async Task<ActionResult> DisplayProduct()
{
Product p = new Product();
p.Name = "Test Product";
p.Type = "USD";
p.Price = 5;
double INR = _currencyService.GetCurrentINR(p.Type);
p.Price = p.Price * INR;
return View(p);
}
}
- I just change one line and our new service is started. Also, after some days, if my client asks me to revert back to ABC service again, I have to change only 1 line.
- If you are plan to use it with Dependency Injection container so it gives us flexibility at whole new level. You don't have to change anything in Controller. We have to just change in dependency injection container and it's done.
Using Unity as Dependency Injection Container
If you don't know about DI or how to use it, please check the following links:
- http://www.codeproject.com/Articles/786332/ASP-NET-MVC-with-Unity-Dependency-Injection
- http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection
Using the Code
UnityConfig.cs Class Configuration (Located in App_Start\UnityConfig.cs)
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<ICurrencyExchangeService , DEFCurrencyExchangeService >();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
- The above code uses unity DI container and we have just changed mapping. Previously,
ICurrencyExchangeService Interface
was pointing to ABCCurrencyExchangeService Class
and now it's pointing to DEFCurrencyExchangeService Class
. The dynamic object creation is done by UNITY DI.
- Now our new Product Controller will look like:
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;
double INR = _currencyService.GetCurrentINR(p.Type);
p.Price = p.Price * INR;
return View(p);
}
}
CodeProject