What is an Interface?
Interface looks like a class, and it contains abstract methods.
By default, all methods are public. Interfaces started with the letter I.
What is the usage of interfaces?
The primary usage of interfaces is to build “loosely coupled” classes and to implement extensibility.
For example, consider if we have a class Person.
public class Person
{
void Greet()
{
Console.WriteLine("The person is greeting 🙋♀️ ✋");
//Greet LOGIC
goes there....
}
}
In the above Person class, we have a logging mechanism and we
use Console.WriteLine to log to the console. But, later, if we decide to log it to
a file instead of console logging. This requires changes in the Person class.
To resolve this, we can move the logging functionality to a
new class, say ConsoleLogger.
public class ConsoleLogger
{
public void LOG(string message)
{
Console.WriteLine(message);
}
}
The Person class will
implement ConsoleLogger as below:
public class Person
{
readonly ConsoleLogger _logger = new ConsoleLogger();
void Greet()
{
_logger.LOG("The person is greeting 🙋♀️ ✋");
//Greet LOGIC
goes there....
}
}
Person class will create a ConsoleLogger instance and invoke ConsoleLogger's method LOG() to log a message.
This is tightly coupled because suppose there is a change in ConsoleLogger class (like log to ETW instead
of a file), then we must change the code in the Person class.
To resolve such problems, we use Interfaces. Instead of Person using ConsoleLogger class, we define an interface ILogger. Loggers can implement Logger interface (ILogger).
When I say loggers, we may have different loggers, such as console logger, file logger.
In the future, if we have to add a new logger
(such as ETW) logger, then we can create a new class for logger and implement
ILogger. Hence Person class will never change. Let’s demonstrate this. I
understand the above statements are quite confusing, but when you see the below
example, you will be very clear about interfaces.
Let us create a
ILogger and logger classes
Public interface ILogger
{
public void LOG(string message);
}
public class ConsoleLogger : ILogger
{
public void LOG(string message)
{
Console.WriteLine(message);
}
}
public class FileLogger : ILogger
{
public void LOG(string message)
{
Console.WriteLine("I ahev to log to a file. For simpleicity, I am using
console here");
}
}
In the Person
class, we have to map the logger and this is done in the constructor as below:
We call this as dependency injection.
public class Person
{
readonly ILogger _logger;
public Person(ILogger logger)
{
_logger = logger;
}
public void Greet()
{
_logger.LOG("The person is greeting 🙋♀️ ✋");
//Greet LOGIC
goes there....
}
}
And in main,
while creating the person object, we have to pass the instance of the logger we
need to use.
static void Main(string[] args)
{
var person = new Person(new ConsoleLogger());
person.Greet();
var person3 = new Person(new FileLogger());
person3.Greet();
}
Interfaces are not for multiple inheritance
Many people claim that unlike C++ where we have multiple inheritance, C# does not support multiple inheritance. To solve this, C# introduces inheritance. This is not right. Because when you inherit from an interface you reuse nothing from interface because we can't implement methods inside interfaces. When we can reuse the code, we are not inheriting anything. This goes against OOPS.
Interfaces are used for building loosely coupled design.
Another important usage is during unit testing.