Posted on Oct 17, 2008

More on Filters as First-class functions.

By expanding (more like enhancing :) ) the filter pattern described here and borrowing some of the beauties of the matcher pattern in Guice, I coded a more concise version of this filter pattern. Now this pattern’s implementation has a fluent API for combining other filters together, a place where all filters can be defined, a way of negating filters, etc. Further in this post I will provide a simple example that describes how the newer version of this pattern can be utilize. But before showing the example, I will provide the pattern’s newer definition and implementation herein.

Filter pattern’s main interface…


public interface Filter <T> {
    Filter <T> and(Filter <? super T> thing);
    Iterable <T> filter(Iterable <T> thing);
    boolean evaluate(T thing);
    Filter <T> or(Filter <? super T> thing);
}

and its abstract implementation…


public abstract class AbstractFilter <T> implements Filter <T> {
    public Filter<T> and(Filter<? super T> thing) {
        return new AndFilter<T>(this, thing);
    }

    public Iterable<T> filter(final Iterable<T> thing) {
        return new Iterable<T>(){
            public Iterator<T> iterator() {
                return new FilteringIterator<T>(
                	AbstractFilter.this,
                	thing.iterator()
                );
            }
        };
    }

    public Filter<T> or(Filter<? super T> thing) {
        return new OrFilter<T>(this, thing);
    }

    private static class AndFilter<T> extends AbstractFilter<T> {
        private final Filter<? super T> one;
        private final Filter<? super T> two;

        AndFilter(
        	Filter<? super T> one,
            Filter<? super T> two
        ) {
            this.one = one;
            this.two = two;
        }

        public boolean evaluate(T thing) {
            return one.evaluate(thing)
            	   && two.evaluate(thing);
        }
    }

    private static class OrFilter<T> extends AbstractFilter<T> {
        private final Filter<? super T> one;
        private final Filter<? super T> two;

        OrFilter(
        	Filter<? super T> one,
            Filter<? super T> two
        ) {
            this.one = one;
            this.two = two;
        }

        public boolean evaluate(T thing) {
            return one.evaluate(thing)
            	   || two.evaluate(thing);
        }
    }

    private static class FilteringIterator<T> implements Iterator <T> {
        private final Filter <T>     filter;
        private final Iterator <T>   base;
        private       T              next;

        FilteringIterator(
        	Filter<T> filter,
        	Iterator<T> base
        ){
            this.filter = filter;
            this.base = base;
            tryNext();
        }

        private void tryNext() {
            next = null;
            while (base.hasNext()) {
                final T item = base.next();
                if (item != null && filter.evaluate(item)) {
                    next = item;
                    break;
                }
            }
        }

        public boolean hasNext() {
            return next != null;
        }

        public T next() {
            if (next == null) throw new NoSuchElementException();
            final T returnValue = next;
            tryNext();
            return returnValue;
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}

Now that I have provided this pattern’s definition and implementation, I will proceed with a simple example of its use. This example will deal with the Java Reflection API. Imagine that you are trying to query all the methods in a class which names start with “eq”, “has”, “toS” and have the Object class as a parameter. Most of the times you will have multiple IFs checking the methods of your interest. What if I don’t want to do that and instead, I want to use the Filter design pattern. Well, in order to do that all you need to code are two basic filters: one for looking at the methods’ names and the other one for looking at the methods’ parameters types.


    public static Filter <Method> containedParameters(final Class<?>... params){
        return new AbstractFilter <Method>(){
            public boolean evaluate(Method thing) {
                final List<Class<?>> s = Arrays.asList(
                	thing.getParameterTypes()
                );

                for(Class<?> each : params){
                    if(s.contains(each)){
                        return true;
                    }
                }
                return false;
            }
        };
    }

    public static Filter <Method> startedWith(final String... prefixes) {
        return new AbstractFilter <Method>(){
            public boolean evaluate(Method thing) {
                for(String prefix : prefixes) {
                    if(thing.getName().startsWith(prefix)){
                        return true;
                    }
                }
                return false;
            }
        };
    }

Simple, huh? totally!
Well, what if you want to negate one of those filters? Well, this is even simpler to implement:


    public static <T> Filter <T> not(final Filter <T> filter) {
        return new AbstractFilter <T>(){
            public boolean evaluate(T thing) {
                return !filter.evaluate(thing);
            }
        };
    }

And to finalize this post, here is how to put these filters to work:


public class RunPattern {
    private RunPattern(){}
    public static void main(String... args) {
        // calling filters one after another
        for(Method each : containedParameters(Object.class)
        	.filter(startedWith("eq", "has", "toS")
        	.filter(Arrays.asList(Object.class.getDeclaredMethods())))){
           System.out.println(each.getName());
        }

        // or maybe you can start using and & or operators
        final Filter <Method> m1 = containedParameters(Object.class)
        						   .and(startedWith("eq", "has", "toS"));

        for(Method each : m1.filter(Arrays.asList(Object.class.getDeclaredMethods()))){
            System.out.println(each.getName());
        }

        // which method do you you prefer?
        // it will be up to you...

        // hmmm....what if?
        final Filter <Method> m2 = not(containedParameters(Object.class))
        						   .and(startedWith("eq", "has", "toS"));
        for(Method each : m2.filter(Arrays.asList(Object.class.getDeclaredMethods()))){
            System.out.println(each.getName());
        }

    }
}

Hopefully you will find this newer version of this pattern useful. Ciao!