6

For the fields that you have as encapsulated members of a class, does it make sense to declare their type to be of the interface that you are using? For example:

public class PayrollInfo
{
  private Map<String, Employee> employees;

  public PayrollInfo()
  {
     employees = new HashMap<>();
  }
}

This gives you maximum flexibility as you can change the implementation of the class easily. However, in my experience programmers normally declare variables to be of the exact type of the class that will be assigned to them, e.g. HashMap in this case. Why is this?

  • 5
    Ack. I don't know what you're asking. I understand your question, but your code sample doesn't make sense to me, and it doesn't seem to say the same thing as your question does. – Robert Harvey May 7 '16 at 19:25
  • 4
    What is not clear about this question? It makes perfect sense to me and the three people who have answered so far all understood it the way I did. – 5gon12eder May 7 '16 at 20:05
  • 6
    They declared a private variable employees to be of type Map (which is an interface) and are asking whether this is any better than declaring its type as HashMap (which is a concrete implementation). – 5gon12eder May 7 '16 at 20:19
  • 6
    Considering no language has been tagged, knowing Map was an interface instead of an actual type was not the least bit obvious. – whatsisname May 8 '16 at 1:50
  • 1
    That is my point - whilst the existing answers are inferring Java-ness and using Java-like examples, they are all language agnostic. interface vs class as language elements don't matter, rather "More abstract" vs "More concrete" is what matters – Caleth May 10 '16 at 15:51
5

It makes a great deal of sense if you assign a value to them from outside the class. Ie.

public class Basket
{
    private IPurchaseService _pServ;
    public Basket(IPurchaseService pServ)
    {
        _pServ = pServ;
    }
}
3

in my experience programmers normally declare variables to be of the exact type of the class that will be assigned to them... Why is this?

IMO it's because they're thinking about the program in a simplistic, non-object-oriented way. Most of the developers that I work with would go the other way, and declare the variable to be Map... instead of HashMap... because when they're using the object, they're only interested in knowing how it will behave---not at all interested in what type of object it actually is.

It's not a big deal when you're talking about a private variable that only exists within a single class, but it becomes a very big deal when it becomes part of a public API. My co-workers probably would reject your example in code review if you declared the variable as HashMap.... Not because a private variable declaration mattered to any other part of the system, but because they'd consider it to be a shallow way of thinking, and they'd want you to get in the habit of thinking on a deeper level.

2

A programmer doing this is probably just following best practise in using interface types instead of concrete types; however, here there is no real advantage to doing that, though because it is private as you noted. (In fact, it is possible that this results in a minor performance penalty when using the field later on.)

Any implementation change of the two lines of code in question (the line that declares and the line that initializes) will be versioned together, so it would be easy to change the type to something else as needed.

This is an area where it might be nice to be able to declare fields using var (C# anyway).

Using var keeps the most possible amount of type information, a local variable declared that way: var employees = new HashMap() would be a reference to a HashMap instance, that also supports the Map interface, without actually having to violate best practice of using interfaces for declarations.

See also: Does the best practice of 'programming to interfaces' apply to local variables?. As you can read for yourself, there are opinions in both directions on this. I think that some fear if programmers don't do this for locals, they will forget to follow this best practise when it really counts, such as for public method parameter & return value types. YMMV.

  • I agree with this analysis. Two remarks: Declaring the field final might help mitigate the “invoke interface” overhead and would be good practice anyway. Otherwise, if you opt for the concrete type, initializing the field at the point of its declaration would maximize locality of the concrete type information to the point where I wouldn't object it at all from a maintainability point of view. It would also be less code to type and you wouldn't risk ending up with nulls. – 5gon12eder May 7 '16 at 19:59
2

Sometimes I do this because the implementation tells the user of the class something important.

One example would be the C# class called ConcurrentDictionary. Depending on how I'm using it, I could use the dictionary using the interface of IDictionary, but doing this makes it less clear to later programmers that the dictionary is thread-safe. (This example does not apply to Java, since ConcurrentMap is an interface, the idea applies)

2

Does it make sense to declare private fields using an interface as their type?

Yes it does. For many reasons.

However, in my experience programmers normally declare variables to be of the exact type of the class that will be assigned to them, e.g. HashMap in this case. Why is this?

Until they've fully written the method they don't know what all it will need access to. You could start with the most restrictive interface and switch to less restrictive as needed. But that will work against code completion tools.

Starting with HashMap as HashMap and later switching to the most restrictive interface theoretically produces the same result. And it means, as you think of new things you need from HashMap, they're right there at your fingertips. Problem is, people who work this way sometimes forget to make the switch.

For some it's easier to think of a HashMap as just a HashMap when writing code. After all you have many other things to think about. Even some well trained OOP programmers do this, not because they think it's good practice but because they don't want to be distracted while writing code. This is selfish because it doesn't hurt them nearly as much as it hurts those who come after. Sometimes they meant to take the time to refactor to the interface but never got around to it. Don't look at code written like this as if it was meant to be this way. This is quick and dirty.

But it's private! No getters. No setters.

It's true that being private means this variables type and its very existence is not visible to the outside world unless it is passed into some outside object. Even in that case the parameter of the method / constructor receiving it is the one that most needs to be as high up the inheritance chain as possible. Not the argument (our variable) being passed in.

However, good coding principles aren't just for between objects. Some can save you a lot of hassle just within one method.

Relevant design principles

  1. Program to an interface, not an implementation
  2. Role interfaces
  3. Make decisions in one place

Program to an interface

Say this variable is used in at least one long hard to read method. If it is declared as a map and not something concrete I can instantly tell that I could refactor to any map implementation without even having to read the long method.

Role interface

If the long method can get by with the variable at an even higher level it should. Do you really need map? Can you get by with one of its super interfaces that exposes less? (Well map doesn't have a super interface but imagine we were talking about list). The less exposed, the higher up it is, the more options you have for hassle free change.

Make decisions in one place

Since I've already shown that I don't want to even read this long ugly method, should it come as a surprise that I don't want to go through it changing a bunch of hashmaps to map? (or some other implementation if I feel like passing on the misery). I don't. I really don't. Please don't make me. Please?

  • I think it's kinda fishy to say "yeah, protect against change of a private field, because when you later on make a mess of a god class that has methods hundreds of lines long it makes it easier to change the type". At this point you're just enabling bad practices. I agree that it's normally best to use interfaces where applicable even for private members, but I don't think this is a very good reason. – sara May 8 '16 at 9:40
  • @kai If I teach you about heat capacity by asking which you'd rather have dumped on your head: a thimble of boiling water or a bucket of boiling water, don't think that means you're safe when it's just one or two thimbles. – candied_orange May 8 '16 at 10:50
1

Always have extendability in mind when coding. Using interfaces in private fields can be a time-saver later on when you...

  1. want to use a setter for the field. This way the user of the setter only needs to conform to the interface.
  2. want to change the implementation inside the class. Imagine one day you find a more performant implementation of Map than HashMap. When refactoring you only need to change the constructor. No worries about any usage of implementation-specific methods.

My rule of a thumb:

If you need some features of the concrete implementation, use it, otherwise stick to the interface.

Note that this applies to built-in types and third-party libs only. For your own code you need to know where your API to the outside world is. To save myself from changing both interfaces and implemantations I use implementations only - until I know I gain some benefits from generating interfaces from classes.

0

programmers normally declare variables to be of the exact type of the class that will be assigned to them

In my experience, there are several reasons for this:

  1. The programmer lacks the understanding/insight to recognize that Map is an interface of HashMap and fails to see that it is even a consideration or option.

  2. The programmer is focused on the need to implement a Map, not on providing flexibility for possible future uses that are not obvious.

  3. The flexibility gains are unnecessary or could even add complexity to an implementation without adding enough value to justify it (a form of pre-optimization).

The third situation is the more important, but I rarely see it. I see a lot of very smart programmers that write very "smart" and "flexible" code and do something like what you illustrate. Then when the code is maintained or needs to be modified at future date, all of those valuable and needed but not so smart programmers out there have no idea what happened or how to take advantage of it. It adds complexity during those future upgrade and/or maintenance phases that is costly.

So, it might be that a very forward looking programmer that was perfectly capable of making a more flexible implementation, instead opted for a more direct and easier to maintain implementation until future demands required a more flexible approach - and better determined the appropriate way to implement that flexibility (e.g. maybe a wrapper class or custom Map implementation is ultimately needed).

does it make sense to declare their type to be of the interface that you are using?

In some cases, it is very useful. However, doing so without an immediate need is unlikely to "improve" the code. In your simplified example the change in the declaration to an interface should be easy and obvious when needed, and fully compatible. In more complex cases, it is probably still best to implement only what is required.

If, however, you are writing system level or API code, you are probably going the right direction if you intend to expose access to this variable in some way and the "end user" of the code may have needs beyond what you can currently define. And it's these cases where it makes a huge difference in the quality of the code to have a quality programmer asking good questions like yours.

0

In addition to Ewan's dependency injection scenario.

If you use The Separated Interface Pattern -

The pattern prescribes that you use different packages for the interface and any of its implementations. Only the definition of the interface is known to any packages that need to consume the functionality.

in such a situation the client/consumer will not have the reference of the concrete implementation at all.

protected by gnat May 10 '16 at 8:19

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.