Interfaces in action
Siva Ram Nyapathi
Software Engineer at Maersk | Pioneering Businesses by Architecting Scalable Solutions | Agile & DevOps Enthusiast | Dedicated Mentor
The phrase "interface" appears frequently in the IT business. What exactly is this nerdy term "Interface"?
Background
What is the relationship between interface and specification?
Interfaces that we use in programming languages are nothing but contracts / specifications.
These are abstract in nature, and are implemented by other classes. There may be many types of implementations for these interfaces, but they will all adhere to the same contract provided by the interface.
In layman's words, if USB is a specification or an interface definition. USB cable manufacturers are free to develop their own cables and peripherals as long as they adhere to USB specifications such as size and voltage. We have gold-plated cables, cables that are extremely long, cables that are extremely short, and so on. They are all finally plugged into a USB port.
Interface In Object Oriented Languages
I am predominantly a java person, hence the java example. Dotnet also have similar syntax but conceptually they are same.
public interface Engine{
public StartStatus startEngine();
public StartStatus stopEngine();
}
The engine here represents an automobile engine, and as we all know, there are many different sorts of engines. The sky is the limit when it comes to petrol engines, diesel engines, and petrol turbo engines, and you can also incorporate fake engines to see how they operate. (This phantom engine becomes vital later on).
public PetrolEngine implements Engine{
public StartStatus startEngine(){
// Do some code with respect to starting of the engine and return StartStatus.
return StartStatus.STARTED;
}
public StartStatus stopEngine(){
// Some logic
return StartStatus.STOPED;
}
}
If you try to compile the preceding class without including the methods in the interface, it will fail. This means that as a PetrolEngine, I must implement the Engine interface and all of its methods, as well as return the StartStatus. The interface in this case does not define how to implement it, but rather shows what it requires.
There will be a line of code like this somewhere within the car class.
var engineE = new PetrolEngine();
engineE.startEngine();
The car class doesn't need to know how its done; all that is required is that it be a class that implements the Engine Interface and performs the methods described in the interface.
Dependency Injection
Interfaces coupled with the concept of dependency injection can make things very flexible yet powerful.
For instance, take an example of a Car with an engine.
class Car {
private DieselEngine engine = new DieselEngine();
// other members
public void start() {
// some logic
engine.start();
}
}
This class is tightly coupled with Diesel Engine, and we need to rewrite the whole logic as car is dependent on the Diesel Engine. This is a dependency
Now let us make one small change and make it better . We can inject the dependency by means of a constructor.
class Car {
private DieselEngine engine;
public Car(DieselEngine engine) {
this.engine= engine;
}
public void start() {
// some logic
engine.start();
}
}
Now we are making some progress, we can now inject all types of diesel engine.
But now that we moving to some environmentally friendly sources of fuel , we would want to keep the engine flexible. For this we will make use of interface. We have specified the contract now , or the contract of the service. Diesel Engine , you being an engine I expect you to start.
领英推荐
interface Engine {
public void start();
}
Now we can replace our code this way
class Car {
private Engine iengine;
public Car(Engine engine) {
this.iengine = engine;
}
public void start() {
// some logic
engine.start();
}
}
If you look at the above code, you will see Car class with an engine interface. Now we have decoupled the service from its implementation. Now lets see how we can further improve.
We can have an electric engine, as it matches the specification of Engine interface. We can replace it .
class ElectricEngine implements Engine {
public void start() {
// Some start logic
}
}
Similarly we have Petrol Engine ,
class PetrolEngine implements Engine {
public void start() {
// Some start logic
}
}
Somewhere in the application where the car object is initialized we just have to change the type.
var car = new Car(new PetrolEngine());
Spring framework takes advantage of this and creates these objects while starting the application and providing the dependent object at run time without needing to create it.
Why is it important?
This is where the concept of Test-Driven Development takes over. If we are to test the car class independently, we will be needing an engine class but if we use a real engine, we will be testing engine logic as well, engine class might have a bug we don't know from Car class's perspective.
To mitigate this problem, we will do something called Mocking / stubbing.
// Initializing mock class
var mockedClass = Mockito.mock(ElectricEngine.class)
// modifying the results when the particular line is excuted
Mockito.when(mockedClass.doSomeMethod().thenReturn(SomeValue)
// we can return any value we like as per the required test case
2. In stubbing we just return the data that is expected
class EngineStub implements Engine{
// some static value logic return a static value
}
DI + Interfaces will give ability to test each Units of code which makes up the system and ensures good testability at the early stage of development itself.
The concept of contract goes beyond code
Following contract can bring us success, it is always to know the rule book to the "T" before we can make new rules or break rules.
Hope this article has given you insights into this powerful concept. Please do let me know your views on this concept.