1

I wrote a builder to set some configurations. One of the builder's method is edit(BusinessObject). Now I got the requirement which leads to the same config except replacing this method by copy(BusinessObject). So the current implementation would be:

public Config editObject(BusinessObject object) {
    return new ConfigBuilder()
        .config1(p1)
        .config2(p2)
        .config3(p3)
        ...
        .edit(object)
        .build();
}

public Config copyObject(BusinessObject object) {
    return new ConfigBuilder()
        .config1(p1)
        .config2(p2)
        .config3(p3)
        ...
        .copy(object)
        .build();
}

class ConfigBuilder {

    ConfigBuilder edit(BusinessObject o) {
        // prepare some settings
        return this;
    }

    ConfigBuilder copy(BusinessObject o) {
        // prepare some other settings
        return this;
    }
}

To avoid duplicated code (except this one line everything else is the same) I want to extract it to a new method with an additional parameter like Function<BusinessObject, ConfigBuilder> prepare.

But I'm stuck how to solve it. The builder instance will be created outside of editObject/copyObject's scope so editOrCopy(object, ConfigBuilder::copy) does not work since this method is not static.

Any ideas?

Stefan Warminski
  • 1,845
  • 1
  • 9
  • 18

2 Answers2

1

I see no reason passing a function in here. Simply extracting common code out should already save your duplicated code. And, imho, it is easier to ready and to understand

private ConfigBuilder commonBuilder() {
    return new ConfigBuilder()
        .config1(p1)
        .config2(p2)
        .config3(p3);
}

public Config editObject(BusinessObject object) {
    return commonBuilder().edit(object).build();
}

public Config copyObject(BusinessObject object) {
    return commonBuilder().copy(object).build();
}
Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
  • For the given information it would work. But in my code I do not use `return new ConfigBuilder()...build()` but I store it in a variable because there is some omitted code below (my fault). – Stefan Warminski Jun 21 '17 at 07:06
0

I got a solution but I'm not very happy with this. I added a static version of the methods with a builder parameter (Thanks to Holger: now I'm happy, there is no need of the static methods):

class ConfigBuilder

    ConfigBuilder edit(BusinessObject o) {
        // prepare some settings
        return this;
    }

    ConfigBuilder copy(BusinessObject o) {
        // prepare some other settings
        return this;
    }
}

Now I can pass the method reference to the newly created method:

private Config modifyObject(BusinessObject object, BiFunction<ConfigBuilder, BusinessObject, ConfigBuilder> modify) {
    return modify.apply(new ConfigBuilder(), object)
        .config1(p1)
        .config2(p2)
        .config3(p3)
        ...
        .build();
}

The invokation is as mentioned in the question

public Config editObject(BusinessObject object) {
    return modifyObject(object, ConfigBuilder::edit);
}

public Config copyObject(BusinessObject object) {
    return modifyObject(object, ConfigBuilder::copy);
}
Stefan Warminski
  • 1,845
  • 1
  • 9
  • 18
  • 1
    The `static` methods are obsolete. Just try what happens when you replace `ConfigBuilder::editStatic` with `ConfigBuilder::edit`, resp. replace `ConfigBuilder::copyStatic` with `ConfigBuilder::copy`. See also [What's the difference between instance method reference types in Java 8?](https://stackoverflow.com/q/22516331/2711488)… – Holger Jun 19 '17 at 16:28
  • Thanks @Holger. I thought I tried it but I think it was with `Function` so I got the compiler error – Stefan Warminski Jun 21 '17 at 06:45