基于不同类型实现谓词链接

时间:2017-08-16 10:28:17

标签: java java-8

我正在寻找链接Predicates并一起测试它们的能力。

思想

我们有谓词的条件(或其他):

 1. P<T>, P<R>, P<S>
 2. P<T>.and(P<T>) => P<T> as result P<T>.test(t1, t2)
 3. P<T>.and(P<R>) => P<T,R> as result P<T,R>.test(t,r)
 4. P<T>.and(P<R>.or(P<S>)) => P<T,R,S> as result P<T,R,S>.test(t,r,s)

我有模特

class User {
            private String name;
            private boolean isActive;
            public User(String name, boolean isActive) {
                this.name = name;
                this.isActive = isActive;
            }
            //getters only...
        }

顺序

public class Order {
        private long createdAt;
        private User user;
        private Manager manager;
        private boolean isApproved;

        public Order(User user, Manager manager, long createdAt, boolean isApproved) {
            this.user = user;
            this.manager = manager;
            this.createdAt = createdAt;
            this.isApproved = isApproved;
        }
        // getters only ...
    }

管理器

class Manager {
        private ManagerCompetency competency;
        private String name;
        public Manager(String name, ManagerCompetency competency) {
            this.name = name;
            this.competency = competency;
        }
        //getters only...
    }

结果我发现了类似的东西 为简短的OrderAcceptanceSpecification OAS

Boolean result = OAS.isUserCanCreateOrder()
                 .and(OAS.isOrderApproved())
                 .and(OAS.isOrderExpiredAfter(3600)).negate()
                 .and(
                     OAS.isOrderApproverCompetentAs(Competencies.HIGH)
                     .or(OAS.isOrderApproverCompetentAs(Competencies.MIDDLE)
                 ).test(Order, Manager, User)

欢迎任何建议/改进。

UPD 我找到了类似的解决方案

public class ChainedPredicate<T> {

    private T t;

    private Predicate<T> predicate;

    public ChainedPredicate(T t, Predicate<T> predicate) {
        Objects.requireNonNull(t);
        Objects.requireNonNull(predicate);
        this.t = t;
        this.predicate = predicate;
    }

    private ChainedPredicate(Predicate<T> predicate) {
        Objects.requireNonNull(predicate);
        this.predicate = predicate;
    }

    public Predicate<T> toPredicate() {
        return t -> test();
    }

    public boolean test() {
        return predicate.test(t);
    }

    public ChainedPredicate<T> and(ChainedPredicate<?> other) {
        Objects.requireNonNull(other);
        return new ChainedPredicate<T>(t -> test() && other.test());
    }

    public ChainedPredicate<T> or(ChainedPredicate<?> other) {
        Objects.requireNonNull(other);
        return new ChainedPredicate<T>(t -> test() || other.test());
    }

    public ChainedPredicate<T> negate() {
        return new ChainedPredicate<T>(toPredicate().negate());
    }
}

执行测试

public class TestChainedPredicate {

    public static void main(String[] args) {

        Predicate<Boolean> tp1 = x -> 1 >0;
        Predicate<String> fp1 = x -> 1 <0;
        Predicate<Integer> fp2 = x -> 1 <0;

        ChainedPredicate<Boolean> p = new ChainedPredicate<Boolean>(true, tp1); //true
        ChainedPredicate<String> p1 = new ChainedPredicate<String>("123", fp1); // false
        ChainedPredicate<Integer> p2 = new ChainedPredicate<Integer>(100, fp2); // false

        boolean result = p.and(p1.or(p2)).test(); // false
        System.out.println(result + " expected : " + false + " : " + ((result==false) ? "OK" : "ERROR") );

        result = p.or(p1.or(p2)).test();
        System.out.println(result + " expected : " + true + " : " + ((result==true) ? "OK" : "ERROR"));

        result = p1.or(p.and(p2)).test();
        System.out.println(result + " expected : " + false + " : " + ((result==false) ? "OK" : "ERROR"));

        result = p1.or(p.or(p2)).test(); // false
        System.out.println(result + " expected : " + true + " : " + ((result==true) ? "OK" : "ERROR"));

        result = p1.or(p.or(p2)).negate().test(); // false
        System.out.println(result + " expected : " + false + " : " + ((result==false) ? "OK" : "ERROR"));

    }

}

2 个答案:

答案 0 :(得分:2)

正如方法签名所示,您只能链接相同类型的谓词。除非您的类共享超类,否则没有解决方法。

Predicate<T> and(Predicate<? super T> other)

Predicate<T> or(Predicate<? super T> other)

答案 1 :(得分:2)

看起来你过于复杂了。您的OrderAcceptanceSpecification可能只包含两种方法:

 static class OrderAcceptanceSpecification {

    static Predicate<Order> isOrderApproved() {
        return Order::isApproved;
    }

    static Predicate<Order> isOrderExpiredAfter(int seconds) {
        return o -> System.nanoTime() - o.createdAt() > seconds;
    }
}

假设您有一个如下所示的类:

 class Order {
    private final Manager manager;
    private final User user;
    ....

您需要的Predicate可以这样写:

Predicate<Order> predicate = OrderAcceptanceSpecification.isOrderApproved()
            .and(x -> x.getUser().isActive())
            .and(OrderAcceptanceSpecification.isOrderExpiredAfter(3600).negate())
            .and(x -> x.getManager().getCompetency().equals(ManagerCompetency.HIGH)
                    || x.getManager().getCompetency().equals(ManagerCompetency.MIDDLE));

我发现||更清洁,而不是将lambda表达式转换为Predicate并链接or