I have a class which implements fluent interface pattern as follows:
Class Rules {
private List<Map<String, String>> listOfMap;
public Rules getListAddresses(List<Map<String, String>> listAddresses) {
listOfMap = new ArrayList<>(listAddresses);
return this;
}
public List<Map<String, String>> fOut() {
return listOfMap;
}
public Rules f1() {
listOfMap = ....;
return this;
}
public Rules f2() {
listOfMap = ....;
return this;
}
...
...
}
I have a few classes that use chaining in the following way.
Class A extends Rules{
List<Map<String, String>> listOfMap = dropActiveStatus(listOfMapInout);
//TODO make some king of CONSTANT to function name mapping
List<Map<String, String>> listOfMapOut = this.getListAddresses(listOfMap)
.f1()
.f2()
.f3()
.f4()
.fOut();
....
}
Class B extends Rules{
List<Map<String, String>> listOfMap = dropActiveStatus(listOfMapInout);
//TODO make some king of CONSTANT to function name mapping
List<Map<String, String>> listOfMapOut = this.getListAddresses(listOfMap)
.f5()
.f6()
.fOut();
....
}
I want to define a generic class instead of multiple classes A, B, C....
How can I enforce that?
I wish if I could define some constants for each method call, and define the constants in order during each classes' constructor, then I can use those constants to invoke the method as per the class's specifcation.
With a functional interface that matches your rule functions f1
, f2
, f3
...:
interface RuleFunction extends Function<Rules, Rules> { }
You can write a single class that will apply whatever combination of rules you pass it:
public class RuleApplier {
private RuleFunction[] steps;
public RuleApplier(RuleFunction... steps) {
Objects.requireNonNull(steps);
this.steps = steps;
}
public List<Map<String, String>> apply(List<Map<String, String>> listOfMap) {
Rules rules = new Rules().getListAddresses(listOfMap);
for (RuleFunction step : steps) {
rules = step.apply(rules);
}
return rules.fOut();
}
}
When you construct the class method references provide a convenient shorthand that can be used to refer to the rules to apply:
List<Map<String, String>> listOfMap = dropActiveStatus(listOfMapInout);
RuleApplier applierA = new RuleApplier(Rules::f1, Rules::f2, Rules::f3, Rules::f4);
List<Map<String, String>> listOfMapOutA = applierA.apply(listOfMap);
RuleApplier applierB = new RuleApplier(Rules::f5, Rules::f6);
List<Map<String, String>> listOfMapOutB = applierB.apply(listOfMap);