Skip to content
Advertisement

How to define a general interface for several type-specific classes?

While trying to program to interfaces, I regularly find myself in the following situation:

  • I have several very similar classes representing containers or algorithms for different types.
  • I would like to define a common interface for these classes.

Consider, e.g., a string container. Such a container will likely have string processing methods. Since those methods are easily represented using generic interfaces, I am ignoring them. Here, I want to focus on methods that can be used to process or provide references to other string containers:

JavaScript

This class can be used just fine in code like:

JavaScript

The problem is: I’m using a concrete class and not an interface to refer to the string container. What if I want to introduce a double container or a list container later and want to leave the rest of the code as is?

Maybe generics could form a solution to this problem? Here is my try. I first define a generic container class:

JavaScript

I then create type-specific implementations of the form:

JavaScript

The above classes can be used as follows:

JavaScript

However, the above approach has several drawbacks:

  1. The consume(Container<String> container) method accepts other types than StringContainer.
  2. In consume(Container<String> container), the parametrized type Container<String> has to be used when processing container. I can’t assign it to StringContainer variables (without type checks or casts).
  3. The alternative consume(StringContainer container) method is defined for StringContainer objects, but can’t be called from a Container<String> reference.
  4. Finally, to me, the line Container<String> stringContainer = new StringContainer(); has an awkward-looking notation that suggests a diamond operator is missing in new StringContainer().

What is the idiomatic way to define a general interface for several type-specific classes, which doesn’t have (all) the above drawbacks?

Should I ignore point 4 and address points 1 and 2 by adding type checks/casts, throwing an UnsupportedOperationException or IllegalArgumentException in case passed objects aren’t StringContainers? Or is there another way to use generics? Can type bounds help me, for example? Or should I look for a solution outside of generics?


Update:

Based on the answers given so far, I have come to realize that I had conflicting goals:

  • On the one hand, I wanted to restrict the types accepted by container methods (as described by points 1 and 2).
  • On the other hand, I wanted to address and pass container types using an interface reference (as hinted at by point 3 and my implicit desire to keep the second main method as is).

I now see that these goals cannot both be reached statically. Since I don’t want to rephrase my question in retrospect, I’ll forget about my second (rather implicit) goal and mark the first-posted solution that addressed points 1 and 2 as the answer.

Advertisement

Answer

Is this what you’re looking for? It’s called a recursive type bound.

JavaScript
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement