Skip to content

Commit d48493e

Browse files
committed
feat: 添加Specification和Validation
1 parent b5109d3 commit d48493e

16 files changed

Lines changed: 350 additions & 0 deletions
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.github.lokic.javaplus.specification;
2+
3+
public class AndSpecification<T> extends CompositeSpecification<T> {
4+
5+
private final Specification<T> leftSpecification;
6+
private final Specification<T> rightSpecification;
7+
8+
public AndSpecification(Specification<T> leftSpecification,
9+
Specification<T> rightSpecification) {
10+
this.leftSpecification = leftSpecification;
11+
this.rightSpecification = rightSpecification;
12+
}
13+
14+
@Override
15+
public boolean isSatisfiedBy(T entity) {
16+
return leftSpecification.isSatisfiedBy(entity)
17+
&& rightSpecification.isSatisfiedBy(entity);
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.github.lokic.javaplus.specification;
2+
3+
public abstract class CompositeSpecification<T> implements Specification<T> {
4+
5+
@Override
6+
public Specification<T> and(Specification<T> specification) {
7+
return new AndSpecification<>(this, specification);
8+
}
9+
10+
@Override
11+
public Specification<T> or(Specification<T> specification) {
12+
return new OrSpecification<>(this, specification);
13+
}
14+
15+
@Override
16+
public Specification<T> not(Specification<T> specification) {
17+
return new NotSpecification<>(specification);
18+
}
19+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.github.lokic.javaplus.specification;
2+
3+
import java.util.function.Function;
4+
5+
public class ExpressionSpecification<T> extends CompositeSpecification<T> {
6+
7+
private final static ExpressionSpecification<?> TRUE_SPEC = new ExpressionSpecification<>(
8+
x -> true);
9+
private final static ExpressionSpecification<?> FALSE_SPEC = new ExpressionSpecification<>(
10+
x -> false);
11+
12+
private final Function<T, Boolean> expression;
13+
14+
public ExpressionSpecification(Function<T, Boolean> expression) {
15+
this.expression = expression;
16+
}
17+
18+
@Override
19+
public boolean isSatisfiedBy(T entity) {
20+
return expression.apply(entity);
21+
}
22+
23+
24+
@SuppressWarnings("unchecked")
25+
public static <T> Specification<T> trueSpec() {
26+
return (Specification<T>) TRUE_SPEC;
27+
}
28+
29+
@SuppressWarnings("unchecked")
30+
public static <T> Specification<T> falseSpec() {
31+
return (Specification<T>) FALSE_SPEC;
32+
}
33+
}
34+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.github.lokic.javaplus.specification;
2+
3+
public class NotSpecification<T> extends CompositeSpecification<T> {
4+
5+
private final Specification<T> specification;
6+
7+
public NotSpecification(Specification<T> specification) {
8+
this.specification = specification;
9+
}
10+
11+
@Override
12+
public boolean isSatisfiedBy(T entity) {
13+
return !specification.isSatisfiedBy(entity);
14+
}
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.github.lokic.javaplus.specification;
2+
3+
public class OrSpecification<T> extends CompositeSpecification<T> {
4+
5+
private final Specification<T> leftSpecification;
6+
private final Specification<T> rightSpecification;
7+
8+
public OrSpecification(Specification<T> leftSpecification,
9+
Specification<T> rightSpecification) {
10+
this.leftSpecification = leftSpecification;
11+
this.rightSpecification = rightSpecification;
12+
}
13+
14+
@Override
15+
public boolean isSatisfiedBy(T entity) {
16+
return leftSpecification.isSatisfiedBy(entity)
17+
|| rightSpecification.isSatisfiedBy(entity);
18+
}
19+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.github.lokic.javaplus.specification;
2+
3+
public interface Specification<T> {
4+
5+
boolean isSatisfiedBy(T entity);
6+
7+
Specification<T> and(Specification<T> specification);
8+
9+
Specification<T> or(Specification<T> specification);
10+
11+
Specification<T> not(Specification<T> specification);
12+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.github.lokic.javaplus.specification;
2+
3+
import com.github.lokic.javaplus.Either;
4+
import com.github.lokic.javaplus.validation.Validation;
5+
import java.util.function.Function;
6+
7+
public class ValidationAdapter<E, T> implements Validation<E, T> {
8+
9+
private final Specification<T> specification;
10+
11+
private final Function<T, E> leftMapper;
12+
13+
public ValidationAdapter(Specification<T> specification, Function<T, E> leftMapper) {
14+
this.specification = specification;
15+
this.leftMapper = leftMapper;
16+
}
17+
18+
@Override
19+
public Either<E, T> validatedBy(T entity) {
20+
if (specification.isSatisfiedBy(entity)) {
21+
return Either.right(entity);
22+
} else {
23+
return Either.left(leftMapper.apply(entity));
24+
}
25+
}
26+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.github.lokic.javaplus.validation;
2+
3+
import com.github.lokic.javaplus.specification.CompositeSpecification;
4+
5+
public abstract class CompositeSpecificationValidation<E, T> extends
6+
CompositeSpecification<T> implements Validation<E, T> {
7+
8+
@Override
9+
public boolean isSatisfiedBy(T entity) {
10+
return validatedBy(entity).isRight();
11+
}
12+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.github.lokic.javaplus.validation;
2+
3+
import com.github.lokic.javaplus.specification.CompositeSpecification;
4+
import com.github.lokic.javaplus.specification.Specification;
5+
6+
public class SpecificationAdapter<E, T> extends CompositeSpecification<T> implements
7+
Specification<T> {
8+
9+
private final Validation<E, T> validation;
10+
11+
public SpecificationAdapter(Validation<E, T> validation) {
12+
this.validation = validation;
13+
}
14+
15+
@Override
16+
public boolean isSatisfiedBy(T entity) {
17+
return validation.validatedBy(entity).isRight();
18+
}
19+
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.github.lokic.javaplus.validation;
2+
3+
4+
import com.github.lokic.javaplus.Either;
5+
import java.util.List;
6+
import java.util.stream.Collectors;
7+
8+
public interface Validation<E, T> {
9+
10+
Either<E, T> validatedBy(T entity);
11+
12+
static <E, T> Either<E, T> failFast(List<Validation<E, T>> validations, T entity) {
13+
return validations.stream()
14+
.reduce(Either.right(entity),
15+
(a, b) -> a.flatMap(b::validatedBy),
16+
(a, b) -> {
17+
throw new IllegalStateException("not support combiner");
18+
});
19+
}
20+
21+
static <E, T> Either<List<E>, T> failOver(List<Validation<E, T>> validations, T entity) {
22+
List<E> lefts = validations.stream()
23+
.map(validation -> validation.validatedBy(entity))
24+
.filter(Either::isLeft)
25+
.map(Either::getLeft)
26+
.collect(Collectors.toList());
27+
if (!lefts.isEmpty()) {
28+
return Either.left(lefts);
29+
}
30+
return Either.right(entity);
31+
}
32+
33+
34+
}

0 commit comments

Comments
 (0)