Some times I see an object instantiated this way.
ICustomer oCustomer = new Customer
Obvious but the Customer class is implementing ICustomer interface in this example. Are there any advantages of instantiating an object that way? From my understanding, if a class in implementing an interface it is already following the contract. What is the name of that practice and is there a disadvantage of instantiating an object “normal”(what I usually do) way? I know there are already some existing questions out there, but they don’t really highlight the advantages and disadvatages
Interface instantiation vs class instantiation
Customer oCustomer = new Customer
9
There is one, very important distinction that I think that you’re overlooking.
The code you provided is for three things: the declaration of a variable, the instantiation of an object, and initializing that variable with that object.
There is no interface implementation here. Customer
needs to implement ICustomer
(or do one or two other tricks) for that to compile successfully, but there’s no actual implementation going on here.
Now that the terminology is out of the way, let’s focus on the meat of the problem: is one better?
This sort of thing falls into the realm of program to an interface. When you declare your variable, you need to give it a type. That type should define the sort of things the variable can do. It is a contract you make with future programmers (or yourself) that oCustomer
can only do these sorts of things. You should decide this contract regardless of the source you use to initialize the variable.
If this variable only needs the interface, then using the interface as its type is clearly defining what it can (and can’t) do. If this variable really needs to be a full Customer
, then double check that you really need that. If you do, then go ahead and make it a Customer
. This provides clear communication to future programmers (or you) that the variable needs to be of that type. And if the variable is just some placeholder for your initializer; if its type doesn’t really matter, then use var
.
The benefits of programming to an interface are described in depth in the link above, but they boil down to allowing you to be flexible. Software inevitably changes. By coding to an interface, you allow this code to remain blissfully unaware when Customer
changes – or if you need tomorrow to initialize oCustomer
with a VipCustomer
instead.
This sort of thing applies in many places throughout programming, not just variable declarations.
9
As long as your code looks as simple like this
void ExampleFunc()
{
ICustomer oCustomer = new Customer();
oCustomer.Method1OfICustomer();
oCustomer.Method2OfICustomer();
// ...
}
there is no semantic difference – you can exchange “ICustomer” by “Customer”, and the behaviour will stay identical. In this example, however, it could fulfill already some documentary purposes. The first line may express the design decision of the programmer to avoid adding calls like
oCustomer.MethodNotPartOfICustomer();
in the future, but in fact, when this kind of call is needed later on, one could also change the “new” line, or add the missing method to the ICustomer
later.
In fact, the use of interfaces, as the term implies, will start to make more sense when there is some real “interfacing” involved – interfacing between functions, classes, components. For example, the function
void ExampleFunc(ICustomer oCustomer)
{
oCustomer.Method1OfICustomer();
oCustomer.Method2OfICustomer();
// ...
}
is probably more generic than
void ExampleFunc(Customer oCustomer)
{
oCustomer.Method1OfICustomer();
oCustomer.Method2OfICustomer();
// ...
}
since it will work with any class implementing the ICustomer
interface, not just Customer
. For example, for testing purposes one could think of passing a “CustomerMock” into the function, something you cannot do with the second variant.
How you create it is not better or worse in any way.
Let’s think about it:
You either set objects or get objects (i.e. passing them into a constructor, method or returning them from a method).
In either case as long as you are providing an interface for setting and getting you can new up your object in any way you want because either way you will be able to leverage polymorphism, abstraction and encapsulation – and that’s the whole point of the whole program to interface not to implementation
principle, which is what your core question is about.
In C# there isn’t much difference.
The difference lies in what you can call on the reference you created.
This code
ICustomer customer = new Customer();
creates an interface reference named customer
to the instance created by the new Customer();
call.
This code
Customer customer = new Customer();
creates an object reference name customer
to the instance created by the new Customer();
call.
While both references point to an instance of the Customer
class, they are different. The interface reference only offers what is defined in the ICustomer
interface, regardless of what else the Customer
class makes available. Using the object reference you can use everything the Customer
class has to offer.
Using an interface reference you would have to cast it back to the implementing class in order to use the “additional” stuff on offer by the class. Something you really do not want to do. After all, when you are passed an interface reference you can’t be certain which class was used to instantiate the object referenced by it. There really is only one exception to this rule: when you just created the interface reference yourself and need to use methods that you do not want to put in the interface because they are only needed during construction/building/initialization of the instance. And even this should be a rare case.
For C# that’s about it.
For languages in which the developer is responsible for explicit lifetime management of the objects that are instantiated (iow having to free each object explicitly), there can be a huge difference between the two ways of referencing the instantiated object.
In Delphi for example, interfaced objects (instances of a class implementing an interface) are reference counted by default and are freed “automatically” when their reference count drops to zero. The reference count is incremented and decremented by _AddRef
and _Release
calls that are added to your code automatically by the compiler.
In Delphi you really do not ever want to create an object reference to an instance of an interfaced class. Doing so means the compiler won’t insert the _AddRef
call that increments the reference count to 1 upon instantiation. Which means the reference count is one too low. Which means the instance will be freed too soon.
That’s why the advice for languages such as Delphi is to never to mix interface and object references and to always use interface references for interfaced classes.
This question goes to the very heart of what Object-Orientation means. Simply put, in a language like Java, C# or Visual Basic.NET, class
es (and struct
s) define Abstract Data Types and interface
s define Objects. As soon as you have a class
or struct
as a type (i.e. the type of a local variable, field, property or a method parameter, a method return type, a type argument to a generic class or interface, the target of a cast operator or the argument of an instanceof
operator), you are not doing object-oriented programming.
The only thing you can use for a type, is an interface
, you can not use class
es or struct
s (and certainly not primitives in a language like Java which has them). The only place where a class
or struct
is allowed, is right next to the new
operator: class
es and struct
s are merely factories for objects.
This is explained much better than I could ever hope to achieve in On Understanding Data Abstraction, Revisited by William R. Cook. It uses Java for the examples, but it applies just as well to C# or any other language.
So, the simple answer is: if you weren’t instantiating an object this way, it wouldn’t be an object, but an instance of an abstract data type.
2