views:

790

answers:

13

I have a friend who's just getting into .NET development after developing in Java for ages and, after looking at some of his code I notice that he's doing the following quite often:

IDictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

He's declaring dictionary as the Interface rather than the Class. Typically I would do the following:

Dictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

I'd only use the IDictionary interface when it's needed (say, for example to pass the dictionary to a method that accepts an IDictionary interface).

My question is: are there any merits to his way of doing things? Is this a common practice in Java?

+8  A: 

If IDictionary is a "more generic" type than Dictionary then it makes sense to use the more generic type in declaring variables. That way you don't have to care as much about the implementing class assigned to the variable and you can change the type easily in the future without having to change a lot of following code. For example, in Java it's often considered better to do

List<Integer> intList=new LinkedList<Integer>();

than it is to do

LinkedList<Integer> intList=new LinkedList<Integer>();

That way I'm sure all following code treats the list as a List and not a LinkedList, making it easy in the future to switch out LinkedList for Vector or any other class which implements List. I'd say this is common to Java and good programming in general.

Chris
+1, but you might want to use the word 'general' rather than 'generic', which already has a bucketload of meaning attached :)
AakashM
+11  A: 

This practice isn't just limited to Java.

It's often used in .NET as well when you want to de-couple the instance of the object from the class you're using. If you use the Interface rather than the Class, you can change the backing type whenever needed without breaking the rest of your code.

You'll also see this practice used heavily with dealing with IoC containers and instanciation using the Factory pattern.

Justin Niessner
But you lose out on all the functionality that Dictionary might provide which is not in IDictionary.
rein
But if you're able to use IDictionary instead...you're not using the functionality to begin with.
Justin Niessner
But if you only need the functionality in IDictionary... It is easier to change IDictionary to Dictionary than the other way around :)
Svish
It's easier to cast a Dictionary to an IDictionary than the other way round. :)
rein
Losing the functionality that Dictionary provides but IDictionary doesn't is the whole point of this idiom. Declaring your local variable as IDictionary forces you to restrict your use of that variable to what is available via the interface. Then, if you later discover you must use some other class that implements IDictionay instead of Dictionary, you can do so by changing the one line that calls the concrete classes constructor (since you know your code only uses it as an IDictionary, not a Dictionary).
Stephen C. Steel
+5  A: 

As far as I've seen Java developers tend to use abstraction (and design patterns) more often than .NET developers. This seems another example of it: why declare the concrete class when he'll essentially only be working with the interface members?

Gergely Orosz
+1  A: 

I've found that for local variables it generally doesn't much matter whether you use the interface or the concrete class.

Unlike class members or method signatures, there is very little refactoring effort if you decide to change types, nor is the variable visible outside its usage site. In fact, when you use var to declare locals, you are not getting the interface type but rather the class type (unless you explicitly cast to the interface).

However, when declaring methods, class members, or interfaces, I think that it will save you quite a bit of headache to use the interface type up front, rather than coupling the public API to a specific class type.

LBushkin
This was my opinion too - for method definitions it's more important to try and use the general type since the method can be reused. For local variables I don't see the merit.
rein
Personally I think the merit is the fact you will spot possible dependencies on implementation classes very easily. Like for example if you pass your local variable to a utility method or something.
NickDK
For local variables, the arguments I've seen are that 1) it keeps you disciplined in using interfaces, and 2) it allows your code to be less sensitive to the return types of function calls that assign to locals - meaning that the function can change the concrete type without impacting your code (so long as the return type still adheres to the interface, of course).
LBushkin
@LBushkin, I also find that as you are developing a method, and you do refactorings like extract method and the like, the concrete type can tend to propagate even though the interface should have been used.
Yishai
+1  A: 

Using interfaces means that "dictionary" in the following code might be any implementation of IDictionary.

Dictionary1 dictionary = new Dictionary1();
dictionary.operation1(); // if operation1 is implemented only in Dictionary1() this will fail for every other implementation

It's best seen when you hide the construction of the object:

IDictionary dictionary = DictionaryFactory.getDictionary(...);
Manrico Corazzi
I would agree that when using a factory to return a non-specific dictionary this is a good idea.
rein
What I meant was that using the interface forces you to think in "generic" terms, enforcing the decoupling of the classes (in my example the method using Dictionary1 has to be familiar with the inner structure of the class, not with the interface)
Manrico Corazzi
+4  A: 

Your friend is following very useful principle:

"Abstract yourself from implementation details"

Vitaliy Liptchinsky
But we're dealing with implementation details. We're not creating an interface to a class - we're simply declaring a local variable.
rein
Not really, IMHO. If interface members is enough for you, I'd really recommend you to stick with interface. Make your code as general, as possible.
Vitaliy Liptchinsky
+3  A: 

In the described situation almost every Java developer would use the interface to declare the variable. The way the Java collections are used is probably one of the best examples:

Map map = new HashMap();
List list = new ArrayList();

Guess it just accomplishes loose coupling in a lot of situations.

NickDK
+1  A: 

Java Collections include a multitude of implementations. Therefore, it's much easier for me to make use of

List<String> myList = new ArrayList<String>();

Then in the future when I realize I need "myList" to be thread safe to simply change this single line to

List<String> myList = new Vector<String>();

And change no other line of code. This includes getters/setters as well. If you look at the number of implementations of Map for example, you can imagine why this might be good practice. In other languages, where there is only a couple implementations for something (sorry, not a big .NET guy) but in Objective-C there is really only NSDictionary and NSMutableDictionary. So, it doesn't make as much sense.

Edit:

Failed to hit on one of my key points (just alluded to it with the getter/setters).

The above allows you to have:

public void setMyList(List<String> myList) {
    this.myList = myList;
}

And the client using this call need not worry about the underlying implementation. Using whatever object that conforms to the List interface that they may have.

MarkPowell
changing that line to: Vector<String> myList = new Vector<String>(); is also only changing one line.
tster
@tster - but what other code calls methods that are specific to ArrayList that would have to be changed because Vector doesn't have the exact same method?
Gordon Tucker
public void setMyList(List<String> list) { myList = list;}Is valid, when declaring it as a List, not so when using a direct implementation. I.e. a client can use whatever list they may have without worrying about converting to your implementation.
MarkPowell
+1  A: 

I've encountered the same situation with a Java developer. He instantiates collections AND objects to their interface in the same way. For instance,

IAccount account = new Account();

Properties are always get/set as interfaces. This causes problems with serialization, which is explained very well here

Jim Schubert
This is only a problem with the "magic" serialization that .NET uses on web service interfaces. The practice of using interfaces instead of concrete classes is perfectly sound.
Daniel Pryden
We've had the problem specifically with ViewState serialization in ASP.NET 1.1
Jim Schubert
+2  A: 

Most often, you see the interface type (IDictionary) used when the member is exposed to external code, whether that be outside the assembly or just outside the class. Typically, most developers use the concrete type internally to a class definition while they expose an encapsulated property using the interface type. In this way, they can leverage the concrete type's capabilities, but if they change the concrete type, the declaring class's interface doesn't need to change.

public class Widget
{
    private Dictionary<string, string> map = new Dictionary<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

later can become:


class SpecialMap<TKey, TValue> : IDictionary<TKey, TValue> { ... }

public class Widget
{
    private SpecialMap<string, string> map = new SpecialMap<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

without changing Widget's interface and having to change other code already using it.

Travis Heseman
+3  A: 

You should always attempt to program to the interface rather than the concrete class.

In Java or any other object oriented programming language.

In .NET world is common to use an I to indicate that is an interface what your're using. I think this is more common because in C# they don't have implements and extends to refer class vs interface inheritance.

I think whey would type

 class MyClass:ISome,Other,IMore 
 { 
 }

And you can tell ISome an IMore are interfaces while Other is a class

In Java there is no need for such a thing

 class MyClass extends Other implements Some, More {
 }

The concept still applies, you should try to code to the interface.

OscarRyz
+1  A: 

For local variables and private fields, which are already implementation details, it's better to use concrete types than interfaces for the declarations because the concrete classes offer a performance boost (direct dispatch is faster than virtual/interface dispatch). The JIT will also be able to more easily inline methods if you don't unnecessarily cast to interface types in the local implementation details. If an instance of a concrete type is returned from a method that returns an interface, the cast is automatic.

280Z28
That is a micro-optimization that should only be performed if you have a specific performance bottleneck to solve, it should not drive design.
Yishai
It's not a micro-optimization. You're already in the implementation where you've chosen a concrete implementation. Why pretend you haven't at the expense of performance?
280Z28
+2  A: 

Coming from a Java world, I agree that the "program to an interface" mantra is drilled into you. By programming to an interface, not an implementation, you make your methods more extensible to future needs.

Anjisan
unless the future need is a change to the contract signature such as a new property or method.
Matthew Whited