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?

Paul Richards
  • 796
  • 7
  • 14
  • 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 07 '16 at 19:25
  • I agree with @RobertHarvey, where are the private interfaces? – Snoop May 07 '16 at 20:02
  • 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 07 '16 at 20:05
  • @5gon12eder maybe I am just confused, but it doesn't look to me like they declared any private interfaces in the code snippet. Isn't that what the question addresses in the first place? – Snoop May 07 '16 at 20:16
  • 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 07 '16 at 20:19
  • @5gon12eder Ahh yeah I see... I was thinking Map was concrete for some reason. – Snoop May 07 '16 at 20:24
  • 9
    Considering no language has been tagged, knowing Map was an interface instead of an actual type was not the least bit obvious. – whatsisname May 08 '16 at 01:50
  • Wondering if this should have the Java tag. The question isn't strictly limited to Java but the example, many answers, and comments are assuming Java. – candied_orange May 08 '16 at 06:57
  • @whatsisname Even if Map were defined using the keyword `class` and not the keyword `interface`, it is providing a common Interface concretized by HashMap and TreeMap and etc. – Caleth May 10 '16 at 09:45
  • @Caleth: the OP didn't indicate a language. How can you be so sure the keyword interface even exists? – whatsisname May 10 '16 at 15:34
  • 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
  • 1
    Possible duplicate of [Why define a Java object using interface (e.g. Map) rather than implementation (HashMap)](https://softwareengineering.stackexchange.com/questions/225674/why-define-a-java-object-using-interface-e-g-map-rather-than-implementation) – gnat Jun 02 '17 at 05:48

9 Answers9

7

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;
    }
}
Ewan
  • 70,664
  • 5
  • 76
  • 161
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.

Solomon Slow
  • 1,213
  • 9
  • 14
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.

Erik Eidt
  • 33,282
  • 5
  • 57
  • 91
  • 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 `null`s. – 5gon12eder May 07 '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)

Patrick M
  • 121
  • 3
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?

candied_orange
  • 102,279
  • 24
  • 197
  • 315
  • 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 08 '16 at 09: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 08 '16 at 10:50
  • @candied_orange, thimble!? – Pacerier May 15 '20 at 14:32
  • @Pacerier little metal cap that fits over a finger to protect it. It’s a [sewing thing](https://en.m.wikipedia.org/wiki/Thimble). – candied_orange May 15 '20 at 14:36
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.

Jim
  • 387
  • 1
  • 6
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.

Kapoor
  • 151
  • 1
  • 4
-1

The general answer is this:

With HashMap obj =new HashMap(), the writer is required to think about HashMap.

With Map obj =new HashMap() he is required to think about Map and HashMap.

Does the scenario justify the added cost? What's the plot?

(The rookies who go "yay now we don't have to think about the class!" ship with additional bugs in their programs.)

Does the added cost result in savings?


In the case of (java.util.) Map vs HashMap, it is unequivocally no. Map is so big and HashMap so small, that you have nothing to save but much overhead to lose if you use both of them within private code.

In the general case of A vs B, if they have a significant difference in size and/or there is a significant amount of private code using A instead of B, then by employing both you gain to the extent of their difference and the amount of code using it.

For example, java.util.Queue vs .LinkedList:

  private LinkedList/Queue obj = new LinkedList();
  obj. //..

Would it be better to leave the variable as LinkedList or to use Queue?

With one line of usage, it can go both ways. But it quickly gets obvious which is a better choice when the amount of code increases:

  private LinkedList/Queue obj = new LinkedList();
  obj. //..
  //..
  //..
  obj. //..
  //..
  //..
  obj. //.. 
  //..
  //..
  obj. //..
  //..
  //..
  obj. //.. 
  //..

The code usage could get so much that you'd need to factor it into it's own function:

    obj. //..
    //..
    //..
    obj. //.. 
    //..
    //..
    Function1(obj);
    //..
    //..
}

private void Function1(Queue obj){
  //..
  //..
  obj. //.. 
  //..
  //..
}

..or even multiple functions:

private void Function1(Queue obj){
  //..
  //..
  obj. //.. 
  //..
  //..
  Function2(obj);
  //..
  Function3(obj);
  //..
  Function4(obj);
  //..
}

When writing all of those code in those functions, the writer never once have to think in terms of LinkedList. The only times when its required to think in terms of LinkedList are at the callsites of those functions.

Since the size difference between Queue and LinkedList is significant and the usage of Queue here plentiful, the overhead of having to think in two separate constructs (compared to simply using LinkedList throughout) is relatively small.

Tldr: For Map vs HashMap, Nopppe.


And it's interesting that this question always appears every now and then yet I see no one ever talking about AbstractMap as if it doesn't even exist, and indeed yes it doesn't need to exist. And if only Map was 10 characters longer and Hashmap 10 characters shorter, no one would be talking about using Map for private code either just as no one talks about AbstractMap because those extra keystrokes would make people realize the obviousness that Map obj = new HashMap() for private code is senselessly redundant. Reminding me of tards who appear with an interface for every single method and every single combination of it ..a tale for another day..

Pacerier
  • 4,973
  • 7
  • 39
  • 58