EDIT: I am not worried about being called in the wrong order since this is enforced through using multiple interfaces, I am just worried about the terminal method getting called
A good way to structure this fluent API pattern is instead of just returning this
from each method, return an instance of a Method Object Pattern
that implements an Interface
that only supports the method that should be next
in the list and have the last method call return the actual object you need.
If that is the only way to get an instance of that object, the last method will always have to be called.
package com.stackoverflow;
import javax.annotation.Nonnull;
import java.util.Date;
public class Q6613429
{
public static void main(final String[] args)
{
final Rights r = PermissionManager.grantUser("me").permissionTo("ALL").item("EVERYTHING").asOf(new Date());
PermissionManager.apply(r);
}
public static class Rights
{
private String user;
private String permission;
private String item;
private Date ofDate;
private Rights() { /* intentionally blank */ }
}
public static class PermissionManager
{
public static PermissionManager.AssignPermission grantUser(@Nonnull final String user)
{
final Rights r = new Rights(); return new AssignPermission() {
@Override
public AssignItem permissionTo(@Nonnull String p) {
r.permission = p;
return new AssignItem() {
@Override
public SetDate item(String i) {
r.item = i;
return new SetDate()
{
@Override
public Rights asOf(Date d) {
r.ofDate = d;
return r;
}
};}
};}
};
}
public static void apply(@Nonnull final Rights r) { /* do the persistence here */ }
public interface AssignPermission
{
public AssignItem permissionTo(@Nonnull final String p);
}
public interface AssignItem
{
public SetDate item(String i);
}
public interface SetDate
{
public Rights asOf(Date d);
}
}
}
This enforces the chain of construction calls, and is very friendly with code completion as it shows what the next interface is and it only method available.
UrlBuilder.java
This provides a foolproof checked exception free way to construct URL
objects.
Creating the object and storing it are different concerns and should not be mixed. Considering that .build()
does not imply .store()
and vice-versa and buildAndStore()
points out the mixing of concerns immediately do the different things in different places and you get the guarantees you want.
Put your call to your persistence code in another method that only accepts a fully constructed instance of Rights
.