Search code examples
javagenericsinheritanceinterfacegeneric-collections

Java - adding functionality to all classes inheriting a specific interface


I'm sorry to say that I cannot describe my problem more to the core or more abstractly. I feel the best way to explain my problem is by means of this quite specific example.

I want to define a function 'readCollection' which would parse a String and give me a specific collection of a specific type, based on how I call the function.

For example, I would like to use it as such:

ArrayList<Foo> fb = readCollection("Foo1\n Foo2\n Foo3\n");

or

LinkedList<Bar> fb = readCollection("Bar1\n Bar2\n Bar3\n");

Of course I have defined an interface for every class which has a 'read' method for reading one instance ("Bar..").

I am caught between a couple of problems:

-naturally the function readCollection should be a static function, but an interface cannot have static methods.

-the method readCollection should return a new object of type Foo or Bar or etc, but I 'cannot instantiate the type', which is generically defined in the class i have defined readCollection.

-supposing the method isn't defined statically, i cannot call it without making reference to a specific object of that type, which I cannot do because of the previous point.

How can I write my method without copying it for each Foo and Bar etc.?

I seem to have found a solution myself, but it is very ugly and nasty.

I now have

public interface Readable<T> {
    public T read(String str); }

and

public class ReadCollection<T extends Readable<T>> {
    public Collection<T> read(File file, Collection<T> ts, T t) {
        ...
        ts.add(t.read(strLine));
        ...
        return ts; 
} }

and

public class Bars extends ReadCollection<Bar>{
    ...
    public static void main(String[] args) {
    new Bars().read(new File("fake/path"), new ArrayList<Bar>(), new Bar()); }

Here I sent along new instances of an ArrayList, to give back the result in, and for Bar, in order to refer te the method 'read'. I cannot see how I could have avoided that.

Please tell me there is a better way. Somewhere I'd like for me to feel very dumb in hindsight.


Solution

  • I'm glad that I'm able to tell you that I have found the final and best answer myself, with the help of your comment (@stevevls) and the help of a friend.

    I now have

    public interface Reader {
        public Reader read(String str); }
    

    so I've removed the generic argument, shich was unneccesary

    public class ReadCollection { // no generic class!
    public static <R extends Reader, C extends Collection<R>> // generic static function! 
            C readColl(File file, Class<? extends C> collClass, Class<? extends R> readClass) {
        C ts = collClass.newInstance()
            Reader t = readClass.newInstance()
            ...
            ts.add(readClass.cast(t.read(strLine)));
            ...
            return ts; 
    } }
    

    and, now I can call the function from anywhere:

    ArrayList<Point> l = ReadCollection.readColl(new File("examples/ex1.csv"), ArrayList.class, Point.class);
    

    (assuming Point implements Reader / has the read-method...)

    without sending along a new instance, and moer importantly: without ever having to extend the class ReadCollection anywhere.

    the problem that the read method cannot be static, cause it is defined in the interface Reader, persists. This is the reason I use readClass.newInstance() etc.

    Still I think this solution is not so ugly anymore.

    Do you guys agree this is a good solution?