The difference is that on second one using an interface you can only access those members which are present on that specific interface instead the whole class. This allows you to implement a few different interfaces on your actual class, whereas only a specific "contrainer" is accessable by the user.
Furthermore interface-driven design is good on unit-testing as you can simply exchange one class by another.
Imagine you have another class that also implements your interface. If a method you created in any context would expect you actual class as parameter you would now have to change that method´s signature in order to also allow instances of your second class. If the method is designed for interfaces instead you can pass both - TestClass
and AnotherTestClass
-instances to it without taking care what type it actual is. This reduces class-coupling as you´re no longer depending on an actual class but only the members an interface defines. How those members are implemented does not have any meaning to your consuming code.
Also take care when casting. Whilst you can say that every instance of TestClass
also implements ITest
not all instances of ITest
are of type TestClass
. Thus the following produces an InvalidCastException
at runtime:
ITest t = new TesClass();
AnotherTestClass t2 = (AnotherTestClass) t;
All in all an interface only says what an instance of that interface can do, but not how it achieves this as this should be unimportant for any consuming code. To stay on your example: your Program
won´t need to know how TotalMarks
is actually implemented as long as it knows that the method actually exists and returns what it is supposed to return. The implementation-details are of no meaning the Program
. This is what is called losly class-coupling.