0

I'm trying to implement the fluet interface pattern. So basicly the idea is to have chaining methods, but i'am mixing it with the strategy pattern, so i can have multiple implementations of "Foo"

I have this abstract class:

public abstract class Foo<T extends BarData> { T data; public Foo(T data) { this.data = data; } public Foo<T> fooMethod { // do stuff with data return this; } } 

This is another implementation of Foo that provides another method:

public class Bar extends Foo<BarData> { public Bar(BarData data) { super(data); } public Bar barMethod() { // do more stuff with data return this; } } 

Fluent Interface:

public interface FluentInterface<T extends BarData, S extends Foo<T>> { S initialize(); } 

Basic implementation:

public class BasicFluentInterfaceImplementation implements FluentApi<BarData, Bar> { @Override Bar initialize() { // prepares data return new Bar(data); } } 

Using all together:

public class Main { public static void main(String[] str) { FluentInterface api = new BasicFluentInterfaceImplementation(); var firstReturn = api.initialize(); // Here it returns Bar var secondReturn = firstReturn.fooMethod(); // As Bar extends Foo i can call the fooMethod() var thirdReturn = secondReturn.barMethod(); // Here is the problem, i can't call the barMethod, because fooMethod already returned an intance of Foo } } 

How can i make Foo return a instance of Bar? Considering that Bar can be anything that extends Foo.

3
  • I think you want class Bar<T extends BarData> extends Foo<T> Commented Sep 17, 2021 at 23:25
  • You can not. Both your FluentInterface#initialize and Foo#fooMethod returns a Foo, and this is where game is over. Commented Sep 17, 2021 at 23:30
  • Also, just a warning: be careful using var along with generics. You could have hard time with wildcard captures. Commented Sep 17, 2021 at 23:33

1 Answer 1

1

I have mostly bad news; there is no real solution to this problem. Fluent interfaces are indeed nice, but this scenario you describe in your question suggests that it's not worth doing here, as it's mostly confusing now, that you can't chain a call to barMethod from fooMethod. Better to just revert back to void-returning methods for such a hierarchy.

There IS a hack available, but, it's.. messy.

public abstract class Foo<T extends BarData, Z extends Foo<T>> { T data; public Foo(T data) { this.data = data; } public Z fooMethod() { // do stuff with data return self(); } @SuppressWarnings("all") protected Z self() { return (Z) this; } } 

Z here is meant to represent 'self', as in, whatever type the object actually is, even in the definition of a supertype. In other words, the return type of self() is supposed to be Bar for an instance of Bar, even though it is defined in Foo.

You unfortunately have to 'mess' with the Z stuff when defining subtypes: class Bar extends Foo<BarData, Bar> {}. The second parameter there is always your own type, it 'makes it work'.

Is this hack worth it to you? Up to you. Don't be too hasty assuming it is.

Sign up to request clarification or add additional context in comments.

2 Comments

Yeah i tried it, but didn't want to use because of the casting. Didn't really get the first idea, you mean like returning the next method?
No, returning nothing - void. Don't have a chainable API - not worth the hassle. It's that, or the snippet as shown in this answer. Note that there is only need for a single method that does the casting (method self()). All others can invoke self(); no casting required.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.