Using the common standard default implementation for advanced plants

I have the following problem:

There is a common 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 these types:

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

For these factories, the default implementation will be provided through Generics:

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

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

 class DefaultT1Factory extends DefaultFactory<T1,T1Factory> { } class DefaultT2Factory extends DefaultFactory<T2,T2Factory> { } 

Before that, it works great. Now the problem. Since T2 is a refinement of T1, Factory for T2 should be used just like Factory for T1.

This requires that T2Factory be obtained from T1Factory. If I do this, I cannot use the DefaultFactory class to implement DefaultT2Factory, because T2Factory is not Factory <T2>. If I add this relation to the extends T2Factory clause, I get an error that the Factory interface is used more than once. But I need a Factory interface in order to be able to use the create method in the default implementation.

In terms of method signatures, everything is fine. As a result, I have to duplicate the default implementation implementation into the Factory implementation. In my case, this encoding is quite large, and I want to avoid code duplication.

Any idea how to get around this problem.

+5
source share
3 answers

I think you meant

Since T2 is a refinement of T1, Factory for T1 should also be used as Factory for T2. A Factory for T1 should not be used as a Factory for T2, because T1 IS NOT T2. However, T2 IS T1, so Factory for T2 can be safely used as Factory T1 (or treated as Factory T1)

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

Now that you are implementing this interface, its cool to say something like

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

Now basically the interface can be parameterized by any type that extends or is T1. In this case, you stated that you want to use T2 in T1.

Hope that helps

+1
source

You can use wildcard to define something like Factory for T or any subtype of T. If you change the signature of DefaultFactory to

 class DefaultFactory<T, F extends Factory<? extends T>> implements Factory<T> { 

Then you should have DefaultFactory<T1, T2Factory> .

0
source

I think I found a solution, not very pretty, but it looks like it works. The answer before this almost works, but use super, not expand. The important point is just to reuse the implementation.

This should be possible while loosening the type constraint for the factory element using super.

 class DefaultFactory<T, F extends Factory<? super T>> { private F factory; @SuppressWarnings("unchecked") public T create() { return (T)factory.create(); } } 

Price is a type of insecurity when calling the create method, which requires an unsafe type. But everything seems to work as expected.

T2Factory should thereby extend T1Factory. Then, unfortunately, this is not Factory <T2>, but this was only required to be able to call the create method in the default implementation, returning the correct type. And for this it is enough to be Factory <T1> (which causes the required type of cast).

0
source

Source: https://habr.com/ru/post/1200392/


All Articles