mercredi 4 novembre 2015

Filtering with truth tables

Imagine a Person class with a boolean flag indicating whether or not the person is employable - set to false by default.

public class Person{
    boolean employable = false;
    ...
}

Now imagine having some external boolean methods which act on Person objects. For example, consider static boolean methods in a utility class.

public class PersonUtil{
    public static boolean ofWorkingAge(Person p){
        if(p.getAge() > 16) return true;
        return false;
    }
    ...
}

Boolean valued static methods in essence analogous to boolean valued functions i.e. predicates.

We can construct a 2^(#predicates)-by-#predicates truth table out of predicates. For example, given three predicates: ofWorkingAge, ofGoodCharacter, isQualified we can construct the following 8-by-3 truth table:

T T T
T T F
T F T
T F F
F T T
F T F
F F T
F F F

We now want to employ people with desirable qualities. Let + indicate that we wish to employ somebody (i.e. set their employability flag to true) and - the opposite.

T T T | +
T T F | +
T F T | +
T F F | -
F T T | +
F T F | -
F F T | -
F F F | -

Now imagine having a collection of Person objects. For each person we adjust their employability flag according to the three predicates. We also update a count (this forces us to use the entire truth table instead of just the positives), so that given 1,000 people we want to end up with something like:

T T T | +   100
T T F | +   200
T F T | +   50
T F F | -   450
F T T | +   50
F T F | -   50
F F T | -   50
F F F | -   50

Presumably this can be thought of as filtering with truth tables. Setting employability flags and updating counts is a rather contrived example but you can easily see how we might instead want to set and update much more complicated things.

QUESTION

Is there a way of elegantly doing this? I can think of two solutions:

Clunky solution

Have a giant hand coded if, else if, else chain.

if(ofWorkingAge && ofGoodCharacter && isQualified){
    c1++;
    p.setEmployable(true)
}
else if(ofWorkingAge && ofGoodCharacter && !isQualified){
    c2++;
    p.setEmployable(true)
}
...
else if(!ofWorkingAge && !ofGoodCharacter && isQualified){
    c7++;
}
else{
    c8++;
}

This is just bad.

Slightly smarter solution

Pass predicates (perhaps in an array) and a collection of sentences to a method. Let the method generate the corresponding truth table. Loop over the people, set their employability, and return an array of counts.

I can see how things could be done with functional interfaces. This SO answer could be used. You could change PrintCommand to IsQualified and pass callCommand a Person instead of a string. But this also seems kindah clunky because we'd then have to have a new interface file for every predicate we come up with.

Is there any other Java 8-ish way of doing this?

Aucun commentaire:

Enregistrer un commentaire