Criterion 对象可以替换为Specification。
规范是一种设计模式,它允许使用布尔运算将标准组合成更复杂的逻辑组合。
假设,我们要过滤所有城市,包括仅具有以下内容的城市:
- 人口高于 X;
- 但低于Y;
- 无论
人口,我们希望包括所有女性较多的城市
然后是男人。
我们需要在某个地方放置如下逻辑:
population > x && population < y || men < women
规范只是一个带有单一方法isSatisfiedBy(city) 的接口,用于确定对象是否符合所有条件并应包含在结果列表中。
interface Specification<T> {
public boolean isSatisfiedBy(T t);
}
那么我们需要一些逻辑组合对象,它们都实现了Specification接口:
class Or<T> implements Specification<T> {
Specification<T> left;
Specification<T> right;
Or(Specification<T> left, Specification<T> right) {
this.left = left;
this.right = right;
}
@Override
public boolean isSatisfiedBy(T t) {
return left.isSatisfiedBy(t) || right.isSatisfiedBy(t);
}
}
class And<T> implements Specification<T> {
Specification<T> left;
Specification<T> right;
And(Specification<T> left, Specification<T> right) {
this.left = left;
this.right = right;
}
@Override
public boolean isSatisfiedBy(T t) {
return left.isSatisfiedBy(t) && right.isSatisfiedBy(t);
}
}
class Not<T> implements Specification<T> {
Specification<T> specification;
Not(Specification<T> specification) {
this.specification = specification;
}
@Override
public boolean isSatisfiedBy(T t) {
return !this.specification.isSatisfiedBy(t);
}
}
然后我们将需要可以指定城市所需属性的基本规范。
class MaxPopulation implements Specification<City> {
private final int max;
MaxPopulation(int max) {
this.max = max;
}
@Override
public boolean isSatisfiedBy(City city) {
return city.getTotal() <= this.max;
}
}
class MinPopulation implements Specification<City> {
private final int min;
MinPopulation(int min) {
this.min = min;
}
@Override
public boolean isSatisfiedBy(City city) {
return city.getTotal() >= this.min;
}
}
class HasMoreMen implements Specification<City> {
@Override
public boolean isSatisfiedBy(City city) {
return city.getMen() >= city.getWomen();
}
}
这些城市规范结合在一起,使用之前定义的逻辑规范,所以我们的组合规范看起来像这样:
Specification<City> spec = new Or<City>(
new And<City> (
new MinPopulation(60000),
new MaxPopulation(100000)
),
new Not<City>(new HasMoreMen())
);
由于过滤很容易,我们只需要向规范传递一个参数:
List<City> filtered = cities.stream().filter(city -> spec.isSatisfiedBy(city))
.collect(Collectors.toList());
for (City eachCity : filtered) {
System.out.println(eachCity.getName());
}
原始问题的标准对象可以表示为规范,但我们可以灵活地以任何我们想要的方式调整业务规则:
Specification<City> criterion = new And<City>(
new And<City>(new MinPopulation(1000), new MaxPopulation(2000)),
new And<City>(new MinFemalePopulation(200), new MaxFemalePopulation(300))
);
(这里需要定义MaxFemalePopulation和MinFemalePopulation)
规范通常使用允许使用“流畅接口”构建规范的构建器模式:
Specification<City> criterion = new SpecBuilder::from(new MinPopulation(1000))
.and(new MaxPopulation(2000))
.and(new MinFemalePopulation(200))
.and()
.build(MaxFemalePopulation(300));
过滤后可以进行排序,因为要排序的项目会更少:
Collections.sort(filtered);
要调用这个方法我们需要我们的城市实现Comparable:
class City implements Comparable<City> {
private String name;
private int total;
private int men;
private int women;
public City(String name, int total, int men, int women) {
this.name = name;
this.total = total;
this.men = men;
this.women = women;
}
public String getName() { return name; }
public int getTotal() { return total; }
public int getMen() { return men; }
public int getWomen() { return women; }
@Override
public int compareTo(City city) {
return this.getName().compareTo(city.getName());
}
}