Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Usage of a common generic default implementation for refined Factories

Tags:

java

generics

I have the following problem:

There is a generic Factory interface

interface Factory<T> {
  T create();
}

Now I have two classes T1 and T2, where T2 is a refinement of T1

class T1 {
}

class T2 extends T1 {
}

and two factories for those types:

interface T1Factory extends Factory<T1> {
  public T1 create();
}

interface T2Factory extends Factory<T2> {
  public T2 create();
}

For those factories a default implementation will be provided via Generics:

class DefaultFactory<T, F extends Factory<T>> implements Factory<T> {
  private F factory;
  ...
  public T create()
  {
    return factory.create();
  }
}

that should be used to implement factories for T1 and T2.

class DefaultT1Factory extends DefaultFactory<T1,T1Factory> {
}

class DefaultT2Factory extends DefaultFactory<T2,T2Factory> {
}

Up to here it works fine. Now the problem. Because T2 is a refinement of T1 the Factory for T2 should be usable also as factory for T1.

This requires T2Factory to be derived from T1Factory. If I do this I cannot use the DefaultFactory class to implement the DefaultT2Factory, because T2Factory is no Factory<T2>. If I add this relationship to the extends clause of T2Factory I got the error that the interface Factory is used more than once. But I need the Factory interface to be able to use the create method in the default implementation.

From the point of method signatures everything is fine. As a consequence I've to duplicate the implementation of the default implementation into the to factory implementation. In my case this coding is quite large and I want to avoid code duplication.

Any idea how to circumvent this problem.

like image 663
Uwe Krüger Avatar asked Nov 10 '22 03:11

Uwe Krüger


1 Answers

I think you meant

Because T2 is a refinement of T1 the Factory for T1 should be usable also as factory for T2. A factory of T1 should not be used as a factory of T2 because T1 IS NOT T2. However T2 IS T1, so a factory for T2 can be safetly used as a factory of T1(or treated as a factory of T1)

   public interface T1Factory<J extends T1> extends Factory<T1> {
             public T1 create();
        }

Now when you implement this interface, its cool to say something like

public class Foo implements T1Factory<T2> {
         public T1 create(){
                    .....
          }
 }

Now basically the interface can be parameterized with any type that extends or is T1. In this case you stated you wanted to take advantage of the T2 is a T1 relationship.

Hope that helps

like image 70
committedandroider Avatar answered Nov 14 '22 23:11

committedandroider