Skip to content

Instantly share code, notes, and snippets.

@cute-jumper
Created October 26, 2017 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cute-jumper/35a8605dd88f78f502db6d6ba7c3c152 to your computer and use it in GitHub Desktop.
Save cute-jumper/35a8605dd88f78f502db6d6ba7c3c152 to your computer and use it in GitHub Desktop.
/**
* Type-safe builder pattern in Java with Phantom Types
*/
public class PhantomType {
private static interface Filled {}
private static interface Empty {}
public static class Builder<T1, T2> {
private String name;
private String address;
private String email;
private Builder(String name, String address, String email) {
this.name = name;
this.address = address;
this.email = email;
}
public static Builder<Empty, Empty> getBuilder() {
return new Builder<Empty, Empty>(null, null, null);
}
// Mandatory field name
public Builder<Filled, T2> setName(String name) {
return new Builder<Filled, T2>(name, address, email);
}
// Mandatory field address
public Builder<T1, Filled> setAddress(String address) {
return new Builder<T1, Filled>(name, address, email);
}
// Optional field email
public Builder<T1, T2> setEmail(String email) {
return new Builder<T1, T2>(name, address, email);
}
}
private String name;
private String address;
private String email;
public PhantomType(Builder<Filled, Filled> builder) {
name = builder.name;
address = builder.address;
email = builder.email;
}
public static void main(String[] args) {
new PhantomType(Builder.getBuilder().setEmail("useless").setName("foo").setAddress("bar"));
// email is optional, i.e., ignoring it won't affect the compilation
new PhantomType(Builder.getBuilder().setAddress("bar").setName("foo"));
// The following two won't compile
//new PhantomType(Builder.getBuilder().setName("foo"));
//new PhantomType(Builder.getBuilder().setAddress("bar"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment