Wednesday, June 09, 2010

Using inheritance with fluent interfaces: get this

Recently I had a situation where I needed to implement Joshua Bloch's Builder pattern (see Effective Java, item 2) over a hierarchy of Java domain objects. Similar problems would arise when building other types of fluent interface, which commonly "return this" from each method in order to support method chaining. Creating a working solution presented some interesting challenges!

Without going into too many details, the fluent Builder pattern is needed in languages without named arguments and default arguments, like Java, in order to avoid long lists of constructor parameters, or a bunch of setters on the object (which may be immutable). For example:

public class X {
protected int foo;
protected int bar;

public static class Builder {
private X x = new X();

public Builder withFoo( int foo ) {
x.foo = foo; return this;
}
public Builder withBar( int bar ) {
x.bar = bar; return this;
}
public X build() { return x; }
}

protected X() {}

public int getFoo() { return foo; }
public int getBar() { return bar; }
}

You would then use this code as follows:

X x = new X.Builder().withFoo( 1 ).withBar( 2 ).build();

Obviously, for a class with only two instance variables, this pattern doesn't make much sense -- you'd just use a constructor. But for domain objects with lots more than two instance variables, or with subclasses that may add more than two, it makes plenty of sense.

However, this becomes more challenging when dealing with objects that use inheritance. In the project I'm working on, we had a number of domain objects that were (legitimately) using inheritance. The trouble is that the builder pattern doesn't particularly handle this well as it stands.

The simplest way of creating builders for inherited classes is simply to duplicate the builder methods:

public class Y extends X {
private int baz;

public static class Builder {
private Y y = new Y();

public Builder withFoo( int foo ) {
y.foo = foo; return this;
}
public Builder withBar( int bar ) {
y.bar = bar; return this;
}
public Builder withBaz( int baz ) {
y.baz = baz; return this;
}
public Y build() { return y; }
}

protected Y() {}

public int getBaz() { return baz; }
}

But duplication is EvilTM, especially if you have lots of builder methods, or lots of subclasses. We really don't want both Builder classes to have the withFoo and withBar methods. How do we get around this?

My first thought was something along the following lines:

public abstract class X {
protected int foo;
protected int bar;

protected static class Builder<T extends X> {
private T x;

public Builder() { x = createX(); }
public Builder<T> withFoo( int foo ) {
x.foo = foo; return this;
}
public Builder<T> withBar( int bar ) {
x.bar = bar; return this;
}
public T build() { return x; }
protected abstract T createX();
}

protected X() {}

public int getFoo() { return foo; }
public int getBar() { return bar; }
}

public class Y extends X {
private int baz;

public static class Builder extends X.Builder<Y> {
public Builder withBaz( int baz ) {
y.baz = baz; return this;
}
protected Y createX() { return new Y(); }
}

protected Y() {}

public int getBaz() { return baz; }
}

The only trouble with that is that the following fails to compile:

Y y = new Y.Builder().withFoo( 1 ).withBaz( 3 ).build();

Why? Because withFoo returns a Builder<Y>, not a Y.Builder; and the withBaz method is on the latter, not the former.

So...the code I actually wrote looked like this:

public abstract class X {
protected int foo;
protected int bar;

protected static class Builder<T extends X,
B extends Builder<T, B>> {

private T obj;

public Builder() { obj = createObj(); }
public B withFoo( int foo ) {
obj.foo = foo; return this;
}
public B withBar( int bar ) {
obj.bar = bar; return this;
}
public T build() { return built; }
protected abstract T createObj();
}

protected X() {}

public int getFoo() { return foo; }
public int getBar() { return bar; }
}

public class Y extends X {
private int baz;

public static class Builder
extends X.Builder<Y, Y.Builder> {

public Builder withBaz( int baz ) {
obj.baz = baz; return this;
}
protected Y createObj() { return new Y(); }
}

protected Y() {}

public int getBaz() { return baz; }
}

Now the return types are correct...but the withFoo and withBar methods won't compile. The trouble is that this inside X.Builder<T, B> is of type X.Builder<T, B>, not of type B. Actually, at runtime, the builder class should indeed be of type B, but it would be inelegant and type-unsafe to cast this to B everywhere.

Happily, there is a solution that doesn't involve casting. This is the final version of the code:

public abstract class X {
protected int foo;
protected int bar;

protected static class Builder<T extends X,
B extends Builder<T, B>> {

private T obj;
private B thisObj;

public Builder() {
obj = createObj(); thisObj = getThis();
}
public B withFoo( int foo ) {
obj.foo = foo; return thisObj;
}
public B withBar( int bar ) {
obj.bar = bar; return thisObj;
}
public T build() { return built; }
protected abstract T createObj();
protected abstract B getThis();
}

protected X() {}

public int getFoo() { return foo; }
public int getBar() { return bar; }
}

public class Y extends X {
private int baz;

public static class Builder
extends X.Builder<Y, Y.Builder> {

public Builder withBaz( int baz ) {
obj.baz = baz; return thisObj;
}
protected Y createObj() { return new Y(); }
protected Builder getThis() { return this; }
}

protected Y() {}

public int getBaz() { return baz; }
}

We added the getThis() method, which is always implemented as return this; in each subclass. This ensures that the Builder subclass is in fact the B type parameter to X.Builder<T, B>.

So, at the price of a small wart (the getThis() method plus associated instance variable), we've got a solution that maintains type safety, removes duplication, and allows all the code completion goodness that your IDE of choice may offer. Win!

429 comments:

«Oldest   ‹Older   401 – 429 of 429
Paid Connections said...

Awesome read! The tips are spot on and very practical—thanks for making it so easy to understand! Secure phone billing solutions

London Structural Repairs said...

Great article! The information is detailed and easy to grasp—thanks for sharing such useful tips! Structural Repairs

Data Analytics Courses In Ontario said...

Looking to boost your career in data science? This post provides a great list of courses available in Iraq that can help you gain the necessary skills to succeed. Don’t wait—start exploring the options here and find the perfect course for your career goals!

P. Zaheer Khan said...

Great insights on using inheritance with fluent interfaces! The approach is powerful for creating readable and intuitive APIs, Looking forward to more posts exploring advanced design patterns like this!
Data science course in Bangalore

Richa said...

Thank you for sharing this detailed post on using inheritance with Fluent NHibernate! Your explanation of how inheritance can be effectively managed in object-relational mapping (ORM) is really helpful. It’s clear that you have a strong understanding of the topic, and your insights will surely benefit many developers working with Fluent NHibernate.
Data science course in Gurgaon

Sunaina kaur said...

I appreciate the detailed approach you took. It made the subject much more approachable.
Data science courses in chennai

AI Readers club said...

Thank you for this great post on using inheritance with Fluent API! Your explanations and examples make it easier to understand how to implement inheritance in a clean and efficient way. This is a helpful resource for developers working with Entity Framework!
Data science courses in Bangladesh

Anonymous said...

Great explanation of using fluent interfaces with inheritance! The step-by-step approach clarifies the complexity and offers a clean solution—thanks for sharing this insightful pattern!
Data science course in Navi Mumbai

NILANJANA B
NBHUNIA8888@gmail.com
Data science course in Navi Mumbai
https://iimskills.com/data-science-courses-in-navi-mumbai/

Shikha iimskills said...

Using inheritance with fluent interfaces can enhance code reuse and maintainability by allowing derived classes to extend base functionality while maintaining a fluent, chainable API. However, careful design is essential to avoid breaking the fluent chain or introducing inconsistencies, as method return types and compatibility across inheritance hierarchies must be ensured.
Thank you for the post.
digital marketing course in Kolkata fees






Gautham34 said...

Cool video with assertion and reason pattern . Enjoyed reading it.
technical writing course

Gautham34 said...

Great explanation and a very interactive post. Thanks for the share.
technical writing course

Gautham34 said...

Very well explained and interactive post.
technical writing course

Data Science Courses In Micronesia said...

Excellent article. the detailed coding are easy to follow. I hope many developers gain knowledge through this article. It is a very useful article. Thanks for sharing.
Data Science Courses in Micronesia

https://iimskills.com/data-science-courses-in-micronesia/

Data Science Courses in Micronesia

Shikha IIMSKILLS said...

Using inheritance with fluent interfaces can enhance code readability and reuse by allowing derived classes to extend and chain method calls seamlessly. It promotes a cleaner, more expressive API design, especially object-oriented programming. However, careful implementation is crucial to avoid complexity or breaking the fluent interface pattern when modifying or extending behaviors in derived classes.
business analyst course in bangalore







A Plumber Service said...

Wonderful post! The information is concise, practical, and very easy to understand—thank you for sharing such valuable tips! Plumbing Services Houston

Chanda said...

Using inheritance with fluent interfaces enables method chaining, enhances code readability, supports polymorphism, and simplifies object configuration, as discussed in Eric's RamblingsMedical Coding Course

sanjana said...

Your example of using inheritance with fluent interfaces is incredibly clear and concise. The code snippets are well-organized and easy to follow.
Medical Coding Courses in Chennai

Best digital marketing institutes in India said...

Your post is incredibly enlightening and thought-provoking. I really appreciate the detailed insights you shared—thank you for your valuable contribution! For hosting details, please visit OneUp Networks.

Judith said...

I'm trying to understand fluent builder pattern by creating the person builder object below.
Medical Coding Courses in Bangalore

IIMskills ( Premkumar vattanavar) said...

After reading your article, i must say thanks. You explained it very well. And I hope that other readers will also experience how I feel after reading your article. Great information.


Medical Coding Course in Hyderabad

IIM SKILLS (Pushpa) said...

Implementing Joshua Bloch's Builder pattern with inheritance in Java can be challenging. This method ensures type safety, prevents duplication, and supports method chaining effectively. An elegant solution!
Medical coding courses in Delhi/

hktechdiary said...

Implementing the Builder pattern with inheritance requires careful handling of method chaining. The challenge is ensuring subclass builders return the correct type while maintaining fluency. Thanks for sharing! Medical Coding Courses in Delhi

tushar kaushik said...

"This post has given me so much to think about! Thanks for the inspiration." Medical Coding Courses in Delhi

Smart Tablet Mount said...

Great blog! I appreciate the effort put into this—well-written and really enjoyable to read.

magnetic tablet wall mount

Wireless Charging Table

Monisha said...

Well-written and packed with useful information!
Medical Coding Courses in Delhi

shreya said...

This post is very simple to read and appreciate without leaving any details out. Great work!
https://iimskills.com/medical-coding-courses-in-bangalore/

Thrisha said...

This was easier to follow than most

Medical Coding Courses in Bangalore

Harsh said...

Great post! I’ve been exploring ways to build Part Time Income, and recently came across Udyogdhan. It’s been super helpful in developing practical digital skills that actually lead to real earning opportunities. If anyone’s looking to start something flexible and skill-based, it’s definitely worth checking out.

laungh new ipad pro said...

i have to learning for lot of information for this sites.
Medical Coding Courses in Delhi

«Oldest ‹Older   401 – 429 of 429   Newer› Newest»