2

In an environment where refactoring is difficult extensibility can be a life saver. However, this is no excuse to over engineer code.

Given that a thin fluent builder method chain is backed by well designed classes that abstract the work away from the method chain, is there much point to making the fluent builder extensible? That is, should it's class(es) implement interface(s) or extend an abstraction as in the getThis() trick. By "thin" I mean to the point where it each chaining method only has one line in it to do the work and one line to return the next object in the chain.

Please consider both the self-referential return this; and step return new nextStep(); styles of method chains.

When the work is abstracted away the only thing left for the method chain class(es) to really define is the chaining (that is, the set of methods and what they return). Having the chained method's class(es) implement interface(s) or use the getThis() trick to use abstract classes seems to just add more complexity for no real benefit since there is no work for the abstract level to do and since the method chaining class(es) are as much an abstraction as an interface would be.

However, this is only seems to be true when the chain is in fact thin. Once real work is hiding in the chain it clearly starts to benefit from being reusable.

Thus it seems like the best way to "extend" (add new methods/steps) these thin fluent builder method chains is to just think up a new name for the chain to start with, and write up a new one from scratch.

Or am I missing something?


design document and example usage

A thin but very simple example of return new nextStep() without interfaces or the getThis() trick.

A thin but less simple example:

public class GotRequiredField {
    public DidRequest doRequest() {
        Request.do(requiredField);
        return new DidRequest();
    }
}

This could be a nested class or full blown class (if given a better name). It works either way so that's just an organizational choice. The class could be extended to change what doRequest() does but Request.do() can also be changed without touching the method chain.

I'm concerned with the situation where I want do add a brand new method. Say after publishing GotRequiredField I want to add an optional withLog(Log log) that returns this to GotRequiredField.

I could extend it and put withLog() in the extending class. Now I have to change everywhere GotRequiredField is instanciated (which for this is only one place). The getThis trick then can be used to ensure that even methods not overriden return the low level implementation instance that has the new method.

I could also try programming to an interface and doing dependency injection but the new method can't be added to the old interface any more than the old class so now I have a new concrete class implementing two interfaces. I don't see how implementing an interface helps me here. I can see using them to do dependency injection to swap out behavior but that doesn't get you new methods, just new behavior.

It's the Open/Closed principle that I'm butting my head against here. What I'd like to do is just break into GotRequiredField and add the new method without touching any of the other methods. But if the class is "closed to modifications" I don't think I'm allowed to do that.

I'm willing to do the work to "future proof" this thing now (cause later will suck) if I can be sure of what I'm buying. I'm just not sure of what I'm buying. I don't want to add anything just `cause it seemed cool.

For example: I've already written and tested nested interfaces over nested classes to do the "next step" chain. It works. It hides the concrete types. But interfaces annoy people trying to statically traverse the code (mostly with ctrl-clicks). And a completely new chain wouldn't have to reuse any of the old chains concrete classes since there isn't much reusable behavior there (it's thin). So I don't want to add interfaces if I have no good explanation of what they are buying us.

Question with similar problem but I'm not sure of the answer

  • This is very abstract. Can you include some hypothetical pseudocode to illustrate your points and make the discussion a bit more concrete? – Robert Harvey Sep 17 '14 at 16:39
  • @RobertHarvey How's this? – candied_orange Sep 18 '14 at 3:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.