Conditional branching with a flowing interface

Premise

Conditional branching in question

This kind of processing that you often see.

//If the string is not empty and is in lowercase letters
//And
//When the processing category is either registered or changed
if ((StringUtils.isNotEmpty(str) && StringUtils.isAlpha(str)
        && StringUtils.isAllLowerCase(str))
        && (processDivision.isRegister() || processDivision.isChange())) {
    //Something processing
}

At a glance, it's hard to tell what the conditions are, and it's easy to make mistakes in the position of parentheses. This may still be better, but I'm desperate when the conditions increase ...

Solved with a flowing interface

Create the following class.

Assume.java


public final class Assume<T> {

    private T obj;

    public static <T> Assume<T> that(T obj) {

        Assume<T> assume = new Assume<>();
        assume.obj = obj;

        return assume;
    }

    public AnyMatch<T> satisfiesAnyOf(Predicate<T> method) {

        AnyMatch<T> anyOf = new AnyMatch<>(obj, method);

        return anyOf;

    }

    public AllMatch<T> satisfiesAllOf(Predicate<T> method) {

        AllMatch<T> allOf = new AllMatch<>(obj, method);

        return allOf;

    }

}

AnyMatch.java


public final class AnyMatch<T> {

    private T obj;

    private boolean match;

    protected AnyMatch(T obj, Predicate<T> checkMethod) {
        this.match = checkMethod.test(obj);
        this.obj = obj;
    }

    public AnyMatch<T> or(Predicate<T> checkMethod) {

        if (match) {
            return this;
        }

        this.match = checkMethod.test(obj);
        return this;
    }

    public boolean check() {

        return match;
    }
}

AllMatch.java


public class AllMatch<T> {

    private T obj;

    private boolean match;

    protected AllMatch(T obj, Predicate<T> checkMethod) {
        this.match = checkMethod.test(obj);
        this.obj = obj;
    }

    public AllMatch<T> and(Predicate<T> checkMethod) {

        if (!match) {
            return this;
        }

        this.match = checkMethod.test(obj);
        return this;
    }

    public boolean check() {
        return match;
    }

}

Using these three, the process at the beginning can be written as follows.

//If the string is not empty and is in lowercase letters
//And
//When the processing category is either registered or changed
if (Assume.that(str)
        .satisfiesAllOf(StringUtils::isNotEmpty)
        .and(StringUtils::isAlpha)
        .and(StringUtils::isAllLowerCase).check()
        && Assume.that(processDivision)
                 .satisfiesAnyOf(ProcessDivision::isRegister)
                 .or(ProcessDivision::isChange).check()) {
    //Something processing
}

The description is longer, but it's easier to understand what you're doing. Should be.

Further improvement

Write a third If statement that is neither an if statement nor a ternary operator Further improvement with reference to the article in.

AnyMatch.java


public final class AnyMatch<T> {
    
    ...

    public <A> Else<A> then(Supplier<A> a1) {
        return (Supplier<A> a2) -> match ? a1.get() : a2.get();
    }
}

Add,

Else.java


public interface Else<A> {
    A orElse(Supplier<A> a2);
}

If you prepare

String hoge = Assume.that(str)
        .satisfiesAllOf(StringUtils::isNotEmpty)
        .and(StringUtils::isAlpha)
        .and(StringUtils::isAllLowerCase).then(() -> "aaa").orElse(() -> "bbb");

You can also do this.

reference

-Write a third If statement that is neither an if statement nor a ternary operator

Recommended Posts

Conditional branching with a flowing interface
A little complicated conditional branching
Exception handling with a fluid interface
Create exceptions with a fluid interface
Realize a decision table without using conditional branching
Program using conditional branching
Conditional branching of numbers
Also complicated conditional branching
Have fun programming with lambda expressions and a fluid interface
A story addicted to toString () of Interface proxied with JdkDynamicAopProxy
A confused story about a ternary operator with multiple conditional expressions
Ruby study memo (conditional branching)
Create a playground with Xcode 12
Draw a gradient with CAGradientLayer
[Ruby] Conditional branching Conditional expression order
java (conditional branching and repetition)
Conditional branch with helper method
A story stuck with NotSerializableException
I made a command line interface with WinMerge Plugin using JD-Core