Статьи

Функциональное программирование: предикат + функция = правило

Я хочу поделиться с вами небольшим гаджетом, который использует google-коллекции . По сути, правило — это условие и действие.
Поэтому я буду использовать Предикат как условие и Функцию как действие. Составная функция тогда состоит из списка правил, для первого предиката, который оценивается как true, она вызовет соответствующую функцию. Если ни один из предикатов не совпадает — будет вызвана функция по умолчанию.

Например, вот как я определяю функцию «размер» произвольного объекта:

Function<Object, Integer> size = new Rules<Object,Integer>().
addRule(isNull(), constant(0)).
addRule(
or(
instanceOf(Collection.class),
instanceOf(Map.class)),
self().reflect("size").cast(Integer.class)).
addRule(
asPredicate(self().reflect("getClass").
reflect("isArray").cast(Boolean.class)),
self().reflect(Array.class, "getLength").cast(Integer.class)).
setDefault(constant(1));

Если вы читали
мой предыдущий пост , вы уже знаете о
FunctionChain , откуда я статически импортирую
self () . Функция
refle () передает Object в Object, вызывая метод без параметров с заданным именем в текущем объекте, или передает текущий объект однопараметрическому методу другого объекта (или классу для статических методов). Метод
cast () выполняет приведение к данному классу. Функция
instanceOf () является ярлыком для
ClassPredicate, который возвращает true, если класс, который он содержит, назначается из данного класса. Я также предполагаю, что статически импортированные
или и является
NULL
Предикаты и
Functions.constant . (Я мог бы заменить
вызовы функций
отражения функциями специального размера и длины, но я думаю, что этого достаточно, чтобы проиллюстрировать идею как она есть.)

Тот же сегмент в «нормальном» кодировании будет выглядеть примерно так:

if (object == null) {
return 0;
} else if (object instanceof Collection) {
return ((Collection)object).size(); {
} else if (object instanceof Map) {
return ((Map)object).size(); {
} else if (object.getClass().isArray()) {
return Array.getLength(object);
} else {
return 1;
}

Я не претендую на то, что одно лучше другого, но, думаю, достаточно интересно и иногда полезно.

Вот исходный код для класса Rules:

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import java.util.Collection;
import java.util.LinkedList;

public class Rules<F,T> extends LinkedList<Rules.Rule<F,T>> implements Function<F,T> {
private Function<? super F, ? extends T> defaultFunction = null;

public Rules() {
super();
}

public Rules(Collection<? extends Rules.Rule<F,T>> c) {
super(c);
}

public Rules<F,T> addRule(Predicate<? super F> condition, Function<? super F, ? extends T> action) {
add(new Rule<F,T>(condition, action));
return this;
}

public Function<? super F, ? extends T> getDefault() {
return defaultFunction;
}

public Rules<F,T> setDefault(Function<? super F, ? extends T> defaultFunction) {
this.defaultFunction = defaultFunction;
return this;
}

public Rules<F,T> noDefault() {
setDefault(null);
return this;
}

public T apply(F from) {
for (Rule<F,T> rule: this) {
if (rule.getPredicate().apply(from)) return rule.getFunction().apply(from);
}
Function<? super F, ? extends T> def = getDefault();
return def != null ? def.apply(from) : null;
}

public static final class Rule<A,B> {
private final Predicate<? super A> predicate;
private final Function<? super A, ? extends B> function;

public Rule(Predicate<? super A> predicate, Function<? super A, ? extends B> function) {
this.predicate = predicate;
this.function = function;
}

public Predicate<? super A> getPredicate() {
return predicate;
}

public Function<? super A, ? extends B> getFunction() {
return function;
}
}

}