I am writing a java (processing) library for unexperienced students, and am looking for the best architecture for implementing it.
Initialization of an object should be as close as possible to this:
myObject = new General("type1");
Such that myObject will become an instance of Type1 which extends General:
class General {
public General() {}
}
class Type1 extends General {
public Type1() {}
}
class Type2 extends General {
public Type1() {}
}
As far as I know, this isn't possible (choosing between extended classes during initialization), but I'm looking for the closest solution possible.
So far, my best solution is to make a static initializer inside General:
class General {
...
static General init (String type) {
General temp;
if (type.equals("type1") {
temp = new Type1();
}
...
return temp;
}
and the initialization is:
General myObject;
myObject = General.init("type1");
This is far from ideal...
thanks.
you can make a factory class that manages initialization.
instead of doing it inside the parent.
// Empty vocabulary of actual object
public interface IPerson
{
string GetName();
}
public class Villager : IPerson
{
public string GetName()
{
return "Village Person";
}
}
public class CityPerson : IPerson
{
public string GetName()
{
return "City Person";
}
}
public enum PersonType
{
Rural,
Urban
}
/// <summary>
/// Implementation of Factory - Used to create objects.
/// </summary>
public class Factory
{
public IPerson GetPerson(PersonType type)
{
switch (type)
{
case PersonType.Rural:
return new Villager();
case PersonType.Urban:
return new CityPerson();
default:
throw new NotSupportedException();
}
}
}
The State design pattern can be a solution here. Rather than the constructor argument changing the type of the object (which isn't possible) it can set a field of the object, to make it behave as if its type is different.
package stackoverflow.questions;
public class Main {
private interface MyInterface {
String foo();
int bar();
}
private static class Type1 implements MyInterface {
#Override public String foo() { return "lorem ipsum "; }
#Override public int bar() { return 6; }
}
private static class Type2 implements MyInterface {
#Override public String foo() { return "dolor sit amet"; }
#Override public int bar() { return 7; }
}
public static class General {
private final MyInterface type;
public General(String type) {
try {
this.type = (MyInterface) Class
.forName("stackoverflow.questions.Main$" + type)
.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Invalid type: " + type);
}
}
public String method1() { return type.foo(); }
public int method2() { return type.bar(); }
}
public static void main(String... args) {
General one = new General("Type1");
General two = new General("Type2");
System.out.println(one.method1() + two.method1());
System.out.println(one.method2() * two.method2());
}
}
I have the following Manager Class with the builder() method:
public class Manager extends Employee {
public static Manager.Builder builder() {
return new ManagerBuilder();
}
public abstract static class Builder<T extends Employee, B extends Builder<T,B>> extends Employee.Builder<T,B>{
}
public static class ManagerBuilder extends Builder<Manager,ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
unfortunatelly trying to build an Object with Manager.builder().age(25).build(); return a Person and not a Manager as I need.
How should I change the Manager.builder() return type to return a Manager and at the same time not clashing with the Employee.builder() Method signature.
The code Employee.builder().age(25).build(); returns Employee, which is fine.
The Employee Class is looking like this:
public class Employee extends Person {
public static Employee.Builder<Employee, EmployeeBuilder> builder() {
return new EmployeeBuilder();
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> extends Person.Builder<T,B>{
}
public static class EmployeeBuilder extends Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Person implements PersonInterface {
private Optional<Integer> age;
protected Person(Builder<?,?> builder) {
this.age = builder.age;
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> {
private Optional<Integer> age;
protected Builder() {
}
public B age(Integer age) {
if (Objects.isNull(age) || age == 0) throw new IllegalArgumentException("Age ist empty");
this.age = Optional.of(age);
return self();
}
protected abstract B self();
public abstract T build();
}
public static class PersonBuilder extends Builder<Person, PersonBuilder>{
#Override
protected PersonBuilder self() {
return this;
}
#Override
public Person build() {
return new Person(this);
}
}
}
The core problem is your strange inheritance structure which overloads the classname Builder. I cant' quite pin the problem down, but at some point your specific type information of ManagerBuilder is lost. This can be simplyfied a lot:
public class Employee extends Person {
public static EmployeeBuilder builder() {
return new EmployeeBuilder();
}
public static class EmployeeBuilder extends Person.Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Manager extends Employee {
public static ManagerBuilder builder() {
return new ManagerBuilder();
}
public static class ManagerBuilder extends Person.Builder<Manager, ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
This should solve a few of your problems.
Now you are left with one more problem. The static method builder is overloaded with incompatible return types. You find information about this at Why does Java enforce return type compatibility for overridden static methods?
If you name those methods differently, it should work.
Well your code works perfectly, and Manager.builder().age(25).build() actually returns a Manager. It is only a compile time problem.
The following Junit test should succeed (it does on my tests):
#Test
public void testEss3() throws Exception {
Person emp = Manager.builder().age(25).build();
assertTrue(emp instanceof Manager);
}
In fact, it looks like as you declare no variable to host the builder, and as the method age is not defined in Manager.Builder nor in its direct subclass Employee.Builder, the Java compiler assume that it will return an object of the class in which it is declared, that is a Person.Builder. It is not false because it is actually an ancestor class. But from that point, the compiler do not know the exact class returned by build() and only knows that it will be a Person.
But the following code is accepter by the compiler:
Manager.Builder<Manager,?> builder = Manager.builder();
Manager emp = builder.age(25).build();
public interface A extends C {
String getCh();
String getId();
String getReview();
}
public interface B extends C {
String getCh();
String getId();
String getReview();
}
#Data
#Builder
public class AImpl implements A{
private String ch;
private String id;
private String review;
}
#Data
#Builder
public class BImpl implements B{
private String ch;
private String id;
private String review;
}
so now to use the builders of these I do:
return AImpl.builder()
.ch("ch")
.id("id")
.review("somerview");
For B I do:
return BImpl.builder()
.ch("ch1")
.id("id1")
.review("some new review");
Is there a way where I can make this builder part into a function? I dont like the idea of repeating the same code again. Like where I can pass id channel and review in a function and I can the object?
Disclaimer: I have never really dealt with builders so there might be a really much better option :D
This approach writes builders for each interface individually.
This does require that the interfaces provide a setter method.
Using generics, the methods of the RootBuilder and BaseABuilder return an instance of the ImplABuilder so that the chain can continue properly.
This is a very simple implementation of the Thistype generic which in other languages exists by default. This implementation also relies on casting to the actual Thistype but if you set the generics properly, that shouldnt be an issue.
public class Test
{
public static void main(String[] args)
{
ImplA implA = ImplA
.builder()
.id("id")
.description("description")
.valueA("a")
.build();
}
}
public interface Root
{
String getId();
void setId(String id);
String getDescription();
void setDescription(String description);
}
public class RootBuilder<Thistype extends RootBuilder<Thistype, Instance>, Instance extends Root>
{
protected final Instance object;
RootBuilder(Instance object)
{
this.object = object;
}
public Thistype id(String value)
{
object.setId(value);
return (Thistype)this;
}
public Thistype description(String value)
{
object.setDescription(value);
return (Thistype)this;
}
public Instance build()
{
return object;
}
}
public interface BaseA extends Root
{
String getValueA();
void setValueA(String valueA);
}
public class BaseABuilder<Thistype extends BaseABuilder<Thistype, Instance>, Instance extends BaseA> extends RootBuilder<Thistype, Instance>
{
protected Instance object;
BaseABuilder(Instance object)
{
super(object);
}
public Thistype valueA(String value)
{
object.setValueA(value);
return (Thistype)this;
}
}
public interface BaseB extends Root
{
String getValueB();
void setValueB(String valueB);
}
public interface BaseC extends Root
{
String getValueC();
void setValueC(String valueC);
}
public final class ImplA implements BaseA
{
private String id;
private String description;
private String valueA;
private ImplA() { }
public static ImplABuilder builder()
{
return new ImplABuilder(new ImplA());
}
private static class ImplABuilder extends BaseABuilder<ImplABuilder, ImplA> // assuming ImplA is final
{
ImplABuilder(ImplA object)
{
super(object);
}
// additional methods for ImplA class
}
}
I want to implement Builder Pattern with inheritance. So I have 4 following classes: one abstract class (ClassA), ClassB, ClassC. TestTest class is used to see how all this works:
public abstract class ClassA {
private String aString;
public String getaString() {
return aString;
}
public abstract class ClassABuilder<T extends ClassABuilder>{
public T setaString(String str) {
ClassA.this.aString = str;
return (T)this;
}
public abstract ClassA build();
}
}
public class ClassB extends ClassA{
private String bString;
public String getbString() {
return bString;
}
public class ClassBBuilder<T extends ClassBBuilder> extends ClassA.ClassABuilder<T>{
public T setbString(String str) {
ClassB.this.bString = str;
return (T)this;
}
#Override
public ClassB build(){
return ClassB.this;
}
}
}
public class ClassC extends ClassB{
private String cString;
public String getcString() {
return cString;
}
public static ClassCBuilder<ClassCBuilder> newBuilder(){
return new ClassC().new ClassCBuilder();
}
public class ClassCBuilder<T extends ClassCBuilder> extends ClassB.ClassBBuilder<T>{
public T setcString(String str) {
ClassC.this.cString = str;
return (T)this;
}
#Override
public ClassC build(){
return ClassC.this;
}
}
}
public class TestTest {
public static void main(String[] args) {
// TODO code application logic here
ClassC C=ClassC.newBuilder()
.setaString(null)
.setbString(null)
.setcString(null) //LINE XXX
.build();
}
}
The problem is that at TestTest at LINE XXX I get can't find symbol "setcString". What do I do wrong?
Let's track it down along the hierarchy:
First consider this signature:
class ClassABuilder<T extends ClassABuilder>
When you call setaString(null) the returned T will be an object that extends ClassABuilder. The compiler knows that this is a ClassBBuilder and thus will allow you to call setbString(null).
However, since the definition states T is required to extend a raw ClassBBuilder only any information on ClassBBuilder's generic types will be lost. Thus the compiler only knows that T is a ClassBBuilder but not that it's actually a ClassCBuilder which extends ClassBBuilder<ClassCBuilder> and hence doesn't know about setcString() on the returned type.
As has already been mentioned, using T extends ClassABuilder<T> will fix that since now the compiler knows there's another generic type to be passed down the hierarchy.
newBuilder() would then have to look like this:
public static ClassCBuilder<?> newBuilder(){
//you have too create a raw type here so you'll have to ignore/suppress/live with the warning
return (new ClassC().new ClassCBuilder());
}
As #AndyTurner already observed, the problem is that you use raw versions of your builder class types as type parameters. He did not go into detail, but the upshot is this:
ClassC C=ClassC.newBuilder() // yields a ClassCBuilder<ClassCBuilder>
.setaString(null) // yields a raw ClassCBuilder (type parameter)
.setbString(null) // yields a raw ClassBBuilder (type parameter bound)
.setcString(null) // ERROR: no such method on ClassBBuilder
.build();
To fix this with minimal change to your class structure and strategy, you must not only correct the type parameter bounds for your builder classes, as Andy advised ...
ClassABuilder<T extends ClassABuilder<T>>
... etc., but also make a change to ClassC.newBuilder(), such as to make it generic:
public static <T extends ClassCBuilder<T>> ClassCBuilder<T> newBuilder() {
return new ClassC().new ClassCBuilder<T>();
}
With that combination of changes, your code compiles for me.
I would like to post here the test demonstrating builder pattern with deep inheritance.
class TypeParamTest {
#Test
void test() {
Dd dd = Dd.builder()
.setIntAa(0)
.setIntBb(1)
.setIntCc(2)
.setIntDd(3)
.build();
assertEquals(0, dd.intAa);
assertEquals(1, dd.intBb);
assertEquals(2, dd.intCc);
assertEquals(3, dd.intDd);
}
abstract static class Aa {
int intAa;
static class AaBuilder<B extends AaBuilder> {
int intAa;
Aa build(Aa aa) {
aa.intAa = intAa;
return aa;
}
B setIntAa(int i) {
this.intAa = i;
return (B) this;
}
}
}
abstract static class Bb extends Aa {
int intBb;
static class BbBuilder<B extends BbBuilder<B>>
extends AaBuilder<B>
{
int intBb;
Bb build(Bb bb) {
bb = (Bb) super.build(bb);
bb.intBb = intBb;
return bb;
}
B setIntBb(int i) {
this.intBb = i;
return (B) this;
}
}
}
static class Cc extends Bb {
int intCc;
static CcBuilder<?> builder() {
return new CcBuilder<>();
}
static class CcBuilder<B extends CcBuilder<B>>
extends BbBuilder<B>
{
int intCc;
Cc build() {
return build(new Cc());
}
Cc build(Cc cc) {
cc = (Cc) super.build(cc);
cc.intCc = intCc;
return cc;
}
B setIntCc(int i) {
this.intCc = i;
return (B) this;
}
}
}
static class Dd extends Cc {
int intDd;
static DdBuilder<?> builder() {
return new DdBuilder<>();
}
static class DdBuilder<B extends DdBuilder<B>>
extends CcBuilder<B>
{
int intDd;
Dd build() {
return build(new Dd());
}
Dd build(Dd dd) {
dd = (Dd) super.build(dd);
dd.intDd = intDd;
return dd;
}
B setIntDd(int i) {
this.intDd = i;
return (B) this;
}
}
}
}
Give this Dr Dobbs article, and the Builder Pattern in particular, how do we handle the case of subclassing a Builder? Taking a cut-down version of the example where we want to subclass to add GMO labelling, a naive implementation would be:
public class NutritionFacts {
private final int calories;
public static class Builder {
private int calories = 0;
public Builder() {}
public Builder calories(int val) { calories = val; return this; }
public NutritionFacts build() { return new NutritionFacts(this); }
}
protected NutritionFacts(Builder builder) {
calories = builder.calories;
}
}
Subclass:
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder extends NutritionFacts.Builder {
private boolean hasGMO = false;
public Builder() {}
public Builder GMO(boolean val) { hasGMO = val; return this; }
public GMOFacts build() { return new GMOFacts(this); }
}
protected GMOFacts(Builder builder) {
super(builder);
hasGMO = builder.hasGMO;
}
}
Now, we can write code like this:
GMOFacts.Builder b = new GMOFacts.Builder();
b.GMO(true).calories(100);
But, if we get the order wrong, it all fails:
GMOFacts.Builder b = new GMOFacts.Builder();
b.calories(100).GMO(true);
The problem is of course that NutritionFacts.Builder returns a NutritionFacts.Builder, not a GMOFacts.Builder, so how do we solve this problem, or is there a better Pattern to use?
Note: this answer to a similar question offers up the classes I have above; my question is regarding the problem of ensuring the builder calls are in the correct order.
You can solve it using generics. I think this is called the "Curiously recurring generic patterns"
Make the return type of the base class builder methods a generic argument.
public class NutritionFacts {
private final int calories;
public static class Builder<T extends Builder<T>> {
private int calories = 0;
public Builder() {}
public T calories(int val) {
calories = val;
return (T) this;
}
public NutritionFacts build() { return new NutritionFacts(this); }
}
protected NutritionFacts(Builder<?> builder) {
calories = builder.calories;
}
}
Now instantiate the base builder with the derived class builder as the generic argument.
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder extends NutritionFacts.Builder<Builder> {
private boolean hasGMO = false;
public Builder() {}
public Builder GMO(boolean val) {
hasGMO = val;
return this;
}
public GMOFacts build() { return new GMOFacts(this); }
}
protected GMOFacts(Builder builder) {
super(builder);
hasGMO = builder.hasGMO;
}
}
Just for the record, to get rid of the
unchecked or unsafe operations warning
for the return (T) this; statement as #dimadima and #Thomas N. talk about, following solution applies in certain cases.
Make abstract the builder which declares the generic type (T extends Builder in this case) and declare protected abstract T getThis() abstract method as follows:
public abstract static class Builder<T extends Builder<T>> {
private int calories = 0;
public Builder() {}
/** The solution for the unchecked cast warning. */
public abstract T getThis();
public T calories(int val) {
calories = val;
// no cast needed
return getThis();
}
public NutritionFacts build() { return new NutritionFacts(this); }
}
Refer to http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ205 for further details.
Based off of a blog post, this approach requires all the non-leaf classes to be abstract, and all the leaf classes must be final.
public abstract class TopLevel {
protected int foo;
protected TopLevel() {
}
protected static abstract class Builder
<T extends TopLevel, B extends Builder<T, B>> {
protected T object;
protected B thisObject;
protected abstract T createObject();
protected abstract B thisObject();
public Builder() {
object = createObject();
thisObject = thisObject();
}
public B foo(int foo) {
object.foo = foo;
return thisObject;
}
public T build() {
return object;
}
}
}
Then, you have some intermediate class that extends this class and its builder, and as many more as you need:
public abstract class SecondLevel extends TopLevel {
protected int bar;
protected static abstract class Builder
<T extends SecondLevel, B extends Builder<T, B>> extends TopLevel.Builder<T, B> {
public B bar(int bar) {
object.bar = bar;
return thisObject;
}
}
}
And, finally a concrete leaf class that can call all the builder methods on any of its parents in any order:
public final class LeafClass extends SecondLevel {
private int baz;
public static final class Builder extends SecondLevel.Builder<LeafClass,Builder> {
protected LeafClass createObject() {
return new LeafClass();
}
protected Builder thisObject() {
return this;
}
public Builder baz(int baz) {
object.baz = baz;
return thisObject;
}
}
}
Then, you can call the methods in any order, from any of the classes in the hierarchy:
public class Demo {
LeafClass leaf = new LeafClass.Builder().baz(2).foo(1).bar(3).build();
}
You can override also the calories() method, and let it return the extending builder. This compiles because Java supports covariant return types.
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder extends NutritionFacts.Builder {
private boolean hasGMO = false;
public Builder() {
}
public Builder GMO(boolean val)
{ hasGMO = val; return this; }
public Builder calories(int val)
{ super.calories(val); return this; }
public GMOFacts build() {
return new GMOFacts(this);
}
}
[...]
}
There is also another way to create classes according to Builder pattern, which conforms "Prefer composition over inheritance".
Define an interface, that parent class Builder will inherit:
public interface FactsBuilder<T> {
public T calories(int val);
}
The implementation of NutritionFacts is almost the same (except for Builder implementing 'FactsBuilder' interface):
public class NutritionFacts {
private final int calories;
public static class Builder implements FactsBuilder<Builder> {
private int calories = 0;
public Builder() {
}
#Override
public Builder calories(int val) {
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
protected NutritionFacts(Builder builder) {
calories = builder.calories;
}
}
The Builder of a child class should extend the same interface (except different generic implementation):
public static class Builder implements FactsBuilder<Builder> {
NutritionFacts.Builder baseBuilder;
private boolean hasGMO = false;
public Builder() {
baseBuilder = new NutritionFacts.Builder();
}
public Builder GMO(boolean val) {
hasGMO = val;
return this;
}
public GMOFacts build() {
return new GMOFacts(this);
}
#Override
public Builder calories(int val) {
baseBuilder.calories(val);
return this;
}
}
Notice, that NutritionFacts.Builder is a field inside GMOFacts.Builder (called baseBuilder). The method implemented from FactsBuilder interface calls baseBuilder's method of the same name:
#Override
public Builder calories(int val) {
baseBuilder.calories(val);
return this;
}
There is also a big change in the constructor of GMOFacts(Builder builder). The first call in the constructor to parent class constructor should pass appropriate NutritionFacts.Builder:
protected GMOFacts(Builder builder) {
super(builder.baseBuilder);
hasGMO = builder.hasGMO;
}
The full implementation of GMOFacts class:
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder implements FactsBuilder<Builder> {
NutritionFacts.Builder baseBuilder;
private boolean hasGMO = false;
public Builder() {
}
public Builder GMO(boolean val) {
hasGMO = val;
return this;
}
public GMOFacts build() {
return new GMOFacts(this);
}
#Override
public Builder calories(int val) {
baseBuilder.calories(val);
return this;
}
}
protected GMOFacts(Builder builder) {
super(builder.baseBuilder);
hasGMO = builder.hasGMO;
}
}
A full 3 level example of multiple builder inheritance would look like this:
(For the version with a copy constructor for the builder see the second example below)
First level - parent (potentially abstract)
import lombok.ToString;
#ToString
#SuppressWarnings("unchecked")
public abstract class Class1 {
protected int f1;
public static class Builder<C extends Class1, B extends Builder<C, B>> {
C obj;
protected Builder(C constructedObj) {
this.obj = constructedObj;
}
B f1(int f1) {
obj.f1 = f1;
return (B)this;
}
C build() {
return obj;
}
}
}
Second level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class2 extends Class1 {
protected int f2;
public static class Builder<C extends Class2, B extends Builder<C, B>> extends Class1.Builder<C, B> {
public Builder() {
this((C) new Class2());
}
protected Builder(C obj) {
super(obj);
}
B f2(int f2) {
obj.f2 = f2;
return (B)this;
}
}
}
Third level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class3 extends Class2 {
protected int f3;
public static class Builder<C extends Class3, B extends Builder<C, B>> extends Class2.Builder<C, B> {
public Builder() {
this((C) new Class3());
}
protected Builder(C obj) {
super(obj);
}
B f3(int f3) {
obj.f3 = f3;
return (B)this;
}
}
}
And an example of usage
public class Test {
public static void main(String[] args) {
Class2 b1 = new Class2.Builder<>().f1(1).f2(2).build();
System.out.println(b1);
Class2 b2 = new Class2.Builder<>().f2(2).f1(1).build();
System.out.println(b2);
Class3 c1 = new Class3.Builder<>().f1(1).f2(2).f3(3).build();
System.out.println(c1);
Class3 c2 = new Class3.Builder<>().f3(3).f1(1).f2(2).build();
System.out.println(c2);
Class3 c3 = new Class3.Builder<>().f3(3).f2(2).f1(1).build();
System.out.println(c3);
Class3 c4 = new Class3.Builder<>().f2(2).f3(3).f1(1).build();
System.out.println(c4);
}
}
A bit longer version featuring a copy constructor for the builder:
First level - parent (potentially abstract)
import lombok.ToString;
#ToString
#SuppressWarnings("unchecked")
public abstract class Class1 {
protected int f1;
public static class Builder<C extends Class1, B extends Builder<C, B>> {
C obj;
protected void setObj(C obj) {
this.obj = obj;
}
protected void copy(C obj) {
this.f1(obj.f1);
}
B f1(int f1) {
obj.f1 = f1;
return (B)this;
}
C build() {
return obj;
}
}
}
Second level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class2 extends Class1 {
protected int f2;
public static class Builder<C extends Class2, B extends Builder<C, B>> extends Class1.Builder<C, B> {
public Builder() {
setObj((C) new Class2());
}
public Builder(C obj) {
this();
copy(obj);
}
#Override
protected void copy(C obj) {
super.copy(obj);
this.f2(obj.f2);
}
B f2(int f2) {
obj.f2 = f2;
return (B)this;
}
}
}
Third level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class3 extends Class2 {
protected int f3;
public static class Builder<C extends Class3, B extends Builder<C, B>> extends Class2.Builder<C, B> {
public Builder() {
setObj((C) new Class3());
}
public Builder(C obj) {
this();
copy(obj);
}
#Override
protected void copy(C obj) {
super.copy(obj);
this.f3(obj.f3);
}
B f3(int f3) {
obj.f3 = f3;
return (B)this;
}
}
}
And an example of usage
public class Test {
public static void main(String[] args) {
Class3 c4 = new Class3.Builder<>().f2(2).f3(3).f1(1).build();
System.out.println(c4);
// Class3 builder copy
Class3 c42 = new Class3.Builder<>(c4).f2(12).build();
System.out.println(c42);
Class3 c43 = new Class3.Builder<>(c42).f2(22).f1(11).build();
System.out.println(c43);
Class3 c44 = new Class3.Builder<>(c43).f3(13).f1(21).build();
System.out.println(c44);
}
}
If you don't want to poke your eye out on an angle bracket or three, or perhaps don't feel you... umm... I mean... cough... the rest of your team will quickly comprehend curiously recurring generics pattern, you can do this:
public class TestInheritanceBuilder {
public static void main(String[] args) {
SubType.Builder builder = new SubType.Builder();
builder.withFoo("FOO").withBar("BAR").withBaz("BAZ");
SubType st = builder.build();
System.out.println(st.toString());
builder.withFoo("BOOM!").withBar("not getting here").withBaz("or here");
}
}
supported by
public class SubType extends ParentType {
String baz;
protected SubType() {}
public static class Builder extends ParentType.Builder {
private SubType object = new SubType();
public Builder withBaz(String baz) {
getObject().baz = baz;
return this;
}
public Builder withBar(String bar) {
super.withBar(bar);
return this;
}
public Builder withFoo(String foo) {
super.withFoo(foo);
return this;
}
public SubType build() {
// or clone or copy constructor if you want to stamp out multiple instances...
SubType tmp = getObject();
setObject(new SubType());
return tmp;
}
protected SubType getObject() {
return object;
}
private void setObject(SubType object) {
this.object = object;
}
}
public String toString() {
return "SubType2{" +
"baz='" + baz + '\'' +
"} " + super.toString();
}
}
and the parent type:
public class ParentType {
String foo;
String bar;
protected ParentType() {}
public static class Builder {
private ParentType object = new ParentType();
public ParentType object() {
return getObject();
}
public Builder withFoo(String foo) {
if (!"foo".equalsIgnoreCase(foo)) throw new IllegalArgumentException();
getObject().foo = foo;
return this;
}
public Builder withBar(String bar) {
getObject().bar = bar;
return this;
}
protected ParentType getObject() {
return object;
}
private void setObject(ParentType object) {
this.object = object;
}
public ParentType build() {
// or clone or copy constructor if you want to stamp out multiple instances...
ParentType tmp = getObject();
setObject(new ParentType());
return tmp;
}
}
public String toString() {
return "ParentType2{" +
"foo='" + foo + '\'' +
", bar='" + bar + '\'' +
'}';
}
}
Key points:
Encapsulate the object in the builder so that inheritance prevents you from setting the field on the object held in the parent type
Calls to super ensure that logic (if any) added to the super type builder methods is retained in the sub types.
Down side is spurious object creation in the parent class(es)... But see below for a way to clean that up
Up side is much easier to understand at a glance, and no verbose constructor transferring properties.
If you have multiple threads accessing your builder objects... I guess I'm glad I'm not you :).
EDIT:
I found a way around the spurious object creation. First add this to each builder:
private Class whoAmI() {
return new Object(){}.getClass().getEnclosingMethod().getDeclaringClass();
}
Then in the constructor for each builder:
if (whoAmI() == this.getClass()) {
this.obj = new ObjectToBuild();
}
The cost is an extra class file for the new Object(){} anonymous inner class
One thing you could do is to create a static factory method in each of your classes:
NutritionFacts.newBuilder()
GMOFacts.newBuilder()
This static factory method would then return the appropriate builder. You can have a GMOFacts.Builder extending a NutritionFacts.Builder, that is not a problem. THE problem here will be to deal with visibility...
I created a parent, abstract generic builder class that accepts two formal type parameters. First is for the type of object returned by build(), the second is the type returned by each optional parameter setter. Below are parent and child classes for illustrative purpose:
// **Parent**
public abstract static class Builder<T, U extends Builder<T, U>> {
// Required parameters
private final String name;
// Optional parameters
private List<String> outputFields = null;
public Builder(String pName) {
name = pName;
}
public U outputFields(List<String> pOutFlds) {
outputFields = new ArrayList<>(pOutFlds);
return getThis();
}
/**
* This helps avoid "unchecked warning", which would forces to cast to "T" in each of the optional
* parameter setters..
* #return
*/
abstract U getThis();
public abstract T build();
/*
* Getters
*/
public String getName() {
return name;
}
}
// **Child**
public static class Builder extends AbstractRule.Builder<ContextAugmentingRule, ContextAugmentingRule.Builder> {
// Required parameters
private final Map<String, Object> nameValuePairsToAdd;
// Optional parameters
private String fooBar;
Builder(String pName, Map<String, String> pNameValPairs) {
super(pName);
/**
* Must do this, in case client code (I.e. JavaScript) is re-using
* the passed in for multiple purposes. Doing {#link Collections#unmodifiableMap(Map)}
* won't caught it, because the backing Map passed by client prior to wrapping in
* unmodifiable Map can still be modified.
*/
nameValuePairsToAdd = new HashMap<>(pNameValPairs);
}
public Builder fooBar(String pStr) {
fooBar = pStr;
return this;
}
#Override
public ContextAugmentingRule build() {
try {
Rule r = new ContextAugmentingRule(this);
storeInRuleByNameCache(r);
return (ContextAugmentingRule) r;
} catch (RuleException e) {
throw new IllegalArgumentException(e);
}
}
#Override
Builder getThis() {
return this;
}
}
This one has met my needs to satisfaction.
The following IEEE contribution Refined Fluent Builder in Java gives a comprehensive solution to the problem.
It dissects the original question into two sub-problems of inheritance deficiency and quasi invariance and shows how a solution to these two sub-problems opens for inheritance support with code reuse in the classical builder pattern in Java.