how to implement fluent builder with inheritance in java - java

problem
I want to create a class with a fluent builder, both of which can be inherited and extended. Base class should have all the common and mandatory fields, children should have different optional fields
simple example below (best, simplistic usecase I could come up with ;p)
base: Animal
name
age
static Builder
impl: Snake extends Animal
length
static Builder extends Animal.Builder
impl: Spider extends Animal
numberOfLegs
static Builder extends Animal.Builder
and I'd like to use it in one of those ways (most preferred one is the first one):
Spider elvis = Spider.name("elvis").age(1).numberOfLegs(8).build();
Spider elvis = Spider.builder().name("elvis").age(1).numberOfLegs(8).build();
Spider elvis = new Spider.Builder().name("elvis").age(1).numberOfLegs(8).build();
what I want to achieve is
user of this builder will have to provide some minimal information (so the system can work without problems), otherwise he won't be able to build that object
all the optional fields can be declared, with no particular order, after mandatory fields are there
it is possible that I'll need to add some mandatory fields for children, but that can be handled with ease by just changing the first method called in the builder
I don't want to have any casts outside those classes (here: in Main), but I don't mind them inside this code (here: in Animal or Spider)
so far I failed and I'd be very grateful if you could please help me find a way out of it :)
or maybe there is just a different approach that I should think about?
most valuable sources I used
http://blog.crisp.se/2013/10/09/perlundholm/another-builder-pattern-for-java
http://egalluzzo.blogspot.com/2010/06/using-inheritance-with-fluent.html
Generic fluent Builder in Java
work done so far
the code so far can be found below. there are some traces of the things I tried and failed, there are some unused or just weird stuff (best example is IBuildImpl). Those are left to give you an understanding of what I tried, but if you think that this needs moderation - please let me know and I'll clean them up
Base
package fafafa;
public abstract class Animal<T> {
String name; //mandatory field, one of many
Integer age; //mandatory field, one of many
public String getName() {
return name;
}
#Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
interface IName {
IAge name(String name);
}
interface IAge {
IBuild age(Integer age);
}
interface IBuild<T extends Animal<T>> {
T build();
}
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>
implements IName, IAge, IBuild<T> {
protected T objectBeingBuilt;
protected abstract B that();
protected abstract T createEmptyObject();
Builder(){
this.objectBeingBuilt = createEmptyObject();
System.out.println();
}
#Override
public IAge name(String name) {
objectBeingBuilt.name = name;
return that();
}
#Override
public IBuild age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
// #Override
// public T build() {
// return objectBeingBuilt;
// }
}
}
Impl
package fafafa;
public class Spider extends Animal<Spider> {
Integer numberOfLegs; //optional field, one of many
private Spider() {
}
public Integer getNumberOfLegs() {
return numberOfLegs;
}
#Override
public String toString() {
return "Spider{" +
"numberOfLegs='" + numberOfLegs + '\'' +
"} " + super.toString();
}
// public static Builder<Spider, Builder> name(String name) {
// return (Builder) new Builder().name(name);
// }
interface INumberOfLegs {
IBuild numberOfLegs(Integer numberOfLegs);
}
interface IBuildImpl extends IBuild<Spider>, INumberOfLegs {
#Override
Spider build();
}
public static class Builder extends Animal.Builder<Spider, Builder> implements IBuildImpl {
#Override
protected Builder that() {
return this;
}
#Override
protected Spider createEmptyObject() {
return new Spider();
}
public IBuild numberOfLegs(Integer numberOfLegs) {
objectBeingBuilt.numberOfLegs = numberOfLegs;
return that();
}
public Spider build() {
return objectBeingBuilt;
}
}
}
Main
package fafafa;
public class Main {
public static void main(String[] args) {
Spider build = new Spider.Builder().name("elvis")
.age(1)
.numberOfLegs(8) //cannot resolve method numberOfLegs
.build();
System.out.println(build);
}
}

Looks like to many generics in a code, I've tried to simplify it a little.
Animal
package come.stackoverflow.builder;
public abstract class Animal {
private final String name; //mandatory field, one of many
private final Integer age; //mandatory field, one of many
Animal(final String name, final Integer age) {this.name = name; this.age = age;}
public String getName() {return name;}
public Integer getAge() {return age;}
#Override public String toString() {return String.format("Animal {name='%s', age='%s'}'", name, age);}
interface IBuild<T> {
T build();
}
public abstract static class AnimalBuilder<B extends AnimalBuilder, T extends Animal> implements IBuild<T> {
String name;
Integer age;
public B name(final String name) {this.name = name; return (B) this;}
public B age(final Integer age) {this.age = age; return (B) this;}
}
}
Spider
package come.stackoverflow.builder;
public class Spider extends Animal {
private final Integer numberOfLegs; //optional field, one of many
private Spider(final String name, final Integer age, final Integer numberOfLegs) {super(name, age); this.numberOfLegs = numberOfLegs;}
public Integer getNumberOfLegs() {return numberOfLegs;}
#Override public String toString() {return String.format("Spider {numberOfLegs='%s'}, %s", getNumberOfLegs(), super.toString());}
public static class SpiderBuilder extends AnimalBuilder<SpiderBuilder, Spider> {
Integer numberOfLegs;
public SpiderBuilder numberOfLegs(final Integer numberOfLegs) {this.numberOfLegs = numberOfLegs; return this;}
public Spider build() {return new Spider(name, age, numberOfLegs);}
}
}
Main Test
import come.stackoverflow.builder.Spider;
public class Main {
public static void main(String[] args) {
Spider build = new Spider.SpiderBuilder()
.name("elvis").numberOfLegs(8).age(1)
.build();
System.out.println(build);
}
}
Execution Result:
Spider {numberOfLegs='8'}, Animal {name='elvis', age='1'}'

The problem of your code is the interface:
interface IAge {
IBuild age(Integer age);
}
This will always return the basic IBuild interface with no parameter, no matter, if the implementation implements it with some argument. Actually even returning it with the parameter wouldn't extend the builder with additional methods.
The parameter in the builder needs to be the extended builder, and not the type to be built.
All interfaces for the common parameters need to be parametrized with it to allow propper continuation.
Here is a suggestion:
1. Don't use IName interface. Replace it with static entry method of the builder
2. Parametrize IAge interface
3. No common builder needed. It can be replaced with inline lambda implementation
Here is the code:
#FunctionalInterface
public interface IAge<B> {
B age(Integer age);
}
public class AnimalBuilder implements IBuild<Animal> {
private final String name;
private final Integer age;
private Integer numberOfLegs;
private AnimalBuilder(String name, Integer age) {
this.name = name;
this.age = age;
}
// Builder entry method
public static IAge<AnimalBuilder> name(String name) {
return age -> new AnimalBuilder(name, age);
}
public AnimalBuilder numberOfLegs(int value) {
numberOfLegs = value;
return this;
}
#Override
public Animal build() {
return new Animal(name, age, numberOfLegs);
}
}
This allows following usage:
AnimalBuilder.name("elvis").age(1).numberOfLegs(8).build();

The problem is in the abstract builder :
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>
implements IName, IAge, IBuild<T> {
...
#Override
public IAge name(String name) {
objectBeingBuilt.name = name;
return that();
}
#Override
public IBuild age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
So, all your concrete builders return the same IBuild<T> interface when you invoke the age() method.
and as you see :
interface IBuild<T extends Animal<T>> {
T build();
}
this interface doesn't allow to return a object where you have methods to set properties with your builder.
When you invoke the name() method, you also don't get the builder :
interface IAge {
IBuild age(Integer age);
}
You should declare age() and name() in the abstract builder like that :
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>{
...
public B name(String name) {
objectBeingBuilt.name = name;
return that();
}
public B age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
In this way, at the compile time, the concrete builder will return the builder of the animal you are creating when you will invokebuilder.age(..).
Besides, I don't understand why having a builder interface for name and another one for age. What is interest to handle IAge and IName interfaces ?
It seems a too low level information to be useful in your builder.
Why not simply declaring you base builder like that :
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>
implements IBuild<T> {
protected T objectBeingBuilt;
protected abstract B that();
protected abstract T createEmptyObject();
Builder(){
this.objectBeingBuilt = createEmptyObject();
System.out.println();
}
public B name(String name) {
objectBeingBuilt.name = name;
return that();
}
public B age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
}
I have not tested the code.

Related

How do I minimize the amount of code for a hierarchy

This is for learning. I have an interface that is implemented by 2 classes, and I am supposed to reduce the amount of code I use in order to keep things more clean and less messy. Currently, the code looks like this:
public abstract class VClass implements IntFace {
protected String name;
public VClass(String name) {
this.name = name;
}
public int value (SClass sc) {//comes from a diff class
return sc.lookup(name);
}
public String getName() {
return name;
}
#Override
public String toString() {
return getName();
}
}
public abstract class NClass extends VClass implements IntFace {
public Number(String name) {
super(name);
this.name = name;
}
public int value (SClass sc) {
return sc.lookup(name);
}
public String getName() {
return name;
}
#Override
public String toString() {
return getName();
}
}
public interface IntFace {
public int value (SClass sc);
public String toString (int num);
}
can this code be more condensed?
You can remove the following things from your code:
implements IntFace from NClass declaration. Since NClass extends VClass, it implements IntFace as well.
this.name = name; from NClass constructor. name is initialized in a superclass constructor
value and getName methods from NClass. These methods are implemented in a superclass.
public modifier from interface methods declaration. Methods in interfaces are public by default.
Now you can also make name field private since it's no longer used in a NClass.

Make method return type generic

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();

Creating a generic function in Java for builders of different implementations of interface

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
}
}

How can I add a protected method to a class implementing an interface in java?

I have a class called Property which has nothing but get-methods. All the fields will be set when a new instance of Propertyis created. Property implements an interface called IProperty.
Due to some bug in a library I use, I have to set the name of an instance of Property anew after its creation. Therefore it was suggested to create a WrapperPropertyclass that will provide a public setName-method which itself calls a therefore created setName()-method in Property, which will be protected/package view.
The problem is that I cannot make this method protected in Property, because Eclipse tells me to add it to the interface IProperty and make it public.
Is there some work-around to it?
WrapperIProperty:
public class WrapperIProperty {
private IProperty prop;
WrapperIProperty(Property prop) {
this.prop = prop;
}
public void setName(String name) {
prop.setName(name);
}
}
Property:
public class Property implements IProperty {
String name;
protected void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getFoobar() {
return 123;
}
public int getWhatever() {
return 987;
}
}
IProperty:
public interface IProperty {
public int getWhatever();
public int getFoobar();
public String getName();
}
This is how it looks at the moment. Obviously it won't work, since I cannot let the method be protected in the Property class. Therefore I best get rid of the interfacee entry somehow. But how?
What you probably want to do is to leave the IProperty interface alone (don't add the setName method to it) and create a delegating wrapper class which provides the method you want (wraps an implementation of the interface).
This way you can feed wrapped properties and regular properties to whatever needs them.
public class WrappedProperty implements IProperty {
private String name;
private Property prop;
WrappedProperty (Property prop) {
this.prop = prop;
}
protected void setName(String name) {
this.name = name;
}
public int getWhatever() {
return prop.getWhatever();
}
public int getFoobar() {
return prop.getFoobar();
}
public String getName() {
if (this.name == null) {
return prop.getName():
} else {
return this.name;
}
}
}
public class Property implements IProperty {
public String getName() {
return "blah";
}
public int getFoobar() {
return 123;
}
public int getWhatever() {
return 987;
}
}
public interface IProperty {
public int getWhatever();
public int getFoobar();
public String getName();
}
Methods in an Interface are public in scope so implementing class cannot override methods by reducing their accessibility. Make them public
You cannot have a public methodName in an Interface and a private or protected methodName in a Class implementing this Interface.
So you can have the methodName public in your Class :
this method do nothing
this method call [another]methodNameProtected (you give another name to a new protected method)
UPDATE
If you want it only in Interface you have to change your Interface in an AbstractClass and put in it the method
public final returnCode methodName if the method is common for all inherited classes
Found the solution to that problem:
WrapperIProperty :
public class WrapperIProperty {
private Property prop;
public WrapperIProperty(IProperty prop) {
this.prop = (Property) prop;
}
public void setName(String name) {
prop.setName(name);
}
}
Property:
public class Property implements IProperty {
private String name = null;
[...]
void setName(String name) {
this.name = name;
}
}
IProperty:
public interface IProperty {
[...]
}
This will do the job

Factory class design issue in java

I have two classes
public class PrepaidPackage {
private String name;
private String serviceClassID;
private boolean isTranferable;
public boolean isTranferable() {
return isTranferable;
}
public void setTranferable(boolean isTranferable) {
this.isTranferable = isTranferable;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getServiceClassID() {
return serviceClassID;
}
public void setServiceClassID(String serviceClassID) {
this.serviceClassID = serviceClassID;
}
}
other class is
public class PostpaidPackage {
private String name;
private boolean isTranferable;
public boolean isTranferable() {
return isTranferable;
}
public void setTranferable(boolean isTranferable) {
this.isTranferable = isTranferable;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I want to create a factory class which on base of package type create relevant class. But if you look at above clasess they dont have same type of methods and variables. So please guide how create interface or abstract class for above class?
Now factory will return class name Package. Would i able to call methods which are not present in other class.
Updates
Please suggest if i break my package into two classes like
public abstract class MyPackage {
public abstract PackageSpec getSpec();
public abstract PackagePrepaidDetails getDetail();
}
Now common attributes will be in PackageSpec and prepaid stuff in packageDetails.
Its kind of abstract factory pattern.
public class PrepaidPackage extends MyPackage{
PackageSpec spec;
public Spec getSpec() {
spec = new PackageSpec();
spec.setTranferable(true)
spec.setName("abc");
return spec;
}
public PackagePrepaidDetails getDetails() {
details = new PackagePrepaidDetails ();
details.setServiceClassID(123)
return details;
}
}
public class PostpaidPackage extends MyPackage{
PackageSpec spec;
public Spec getSpec() {
spec = new PackageSpec();
spec.setTranferable(true)
spec.setName("abc");
return spec;
}
}
I recomment you to have an interface if you don't have already. You do not neccessarily need it, but it is a good practice if they are so similar:
public interface Package {
public boolean isTranferable();
public void setTranferable(boolean isTranferable);
public String getName();
public void setName(String name);
}
Then in your calling code, you have a Package from your factory and:
Package p = myFactory.nextPackage(); // or something
if (p instanceof PrepaidPackage) {
PrepaidPackage prepaid = (PrefpaidPackage)p;
// and do the thing you want
} else if (p instanceof PostpaidPackage) {
PostpaidPackage postpaid = (PostpaidPackage)p;
// amd do the other things
}
Thing you are recommended to llok into is the instanceof operator and type casting.
A quick fix, not an ideal one is to have an interface that represents all the methods in the Prepaid class and leave them unimplemented in the Postpaid. That will solve the problem in the short term. I would suggest that you have a relook of the classes and the usages to avoid unimplemented methods in the code.
Well for an abstract super class you have to group everything common to both :
public abstract class MyPackage { // not sure you can call a class just "Package"
private String name;
private boolean isTranferable;
public boolean isTranferable() {
return isTranferable;
}
public void setTranferable(boolean isTranferable) {
this.isTranferable = isTranferable;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
then both inherits from it (the first adds serviceClassID and the second nothing)
your factory function will return a MyPackage (or AbstractPackage, whatever), but to access the specific function you'll have to cast after an instanceof test.
Two possible design choices you can make:
Have the prepaid package extend
postpaid package and your factory
then returns objects of type
postpaid package, the code which
calls the factory is then
responsible for inspecting the type.
Have a package interface which
defines all of the methods and have
postpaid package define the methods
to throw an
UnsupportedOperationException (ala
the way collections defines some
operations as optional.) or return
some kind of sentinel value (i.e. null)
For either of the above you could add another method getType() which returns an enum of the various package types you wish to implement, and this could then be used in the code that accesses the factory objects to determine which methods are available.

Categories

Resources