设计模式实战:过滤器模式(Criteria Pattern)详解
在开发中,我们经常需要根据不同的条件从集合中筛选出特定的数据。如果每次都要写一堆 if-else,代码会变得难以维护。过滤器模式(Filter Pattern),也叫标准模式(Criteria Pattern),提供了一种解耦的方式,让我们能用不同的标准来过滤对象,并且可以通过逻辑运算把这些标准组合起来。
核心思路
这个模式的核心在于定义一个 Criteria 接口,所有具体的筛选条件都实现它。这样我们就可以灵活地创建任意数量的筛选类,甚至编写组合筛选类(比如'既是男性又是单身')。最终返回的都是筛选过的数据列表。
代码实现
下面是一个完整的 Java 示例,展示了如何构建这套机制。
1. 定义实体类
首先需要一个被筛选的对象,这里用 Person 代表。包含姓名、性别和婚姻状态。
import java.util.ArrayList;
import java.util.List;
public class Person {
private String name;
private String gender;
private String maritalStatus;
public Person(String name, String gender, String maritalStatus) {
this.name = name;
this.gender = gender;
this.maritalStatus = maritalStatus;
}
@Override
public String toString() {
return "Person{name='" + name + "', gender='" + gender + "', maritalStatus='" + maritalStatus + "'}";
}
public String getName() { return name; }
public String getGender() { return gender; }
public String getMaritalStatus() { return maritalStatus; }
}
2. 定义 Criteria 接口
这是过滤器的契约,接收一组对象,返回满足条件的子集。
interface Criteria {
List<Person> meetCriteria(List<Person> persons);
}
3. 具体筛选条件
我们可以为性别、婚姻状态分别实现具体的筛选逻辑。注意这里使用了 equalsIgnoreCase 来处理大小写问题。
class CriteriaMale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> malePerson = new ArrayList<>();
for (Person person : persons) {
if (person.getGender().equalsIgnoreCase("male")) {
malePerson.add(person);
}
}
return malePerson;
}
}
class CriteriaFemale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> femalePerson = new ArrayList<>();
for (Person person : persons) {
if (person.getGender().equalsIgnoreCase("female")) {
femalePerson.add(person);
}
}
return femalePerson;
}
}
class CriteriaSingle implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> filteredList = new ArrayList<>();
for (Person person : persons) {
if (person.getMaritalStatus().equalsIgnoreCase("single")) {
filteredList.add(person);
}
}
return filteredList;
}
}
4. 组合筛选逻辑
这才是模式的精髓。我们可以把两个标准组合成'且'或'或'的关系。
AndCriteria:需要同时满足两个条件。先应用第一个条件,再对结果应用第二个条件。
class AndCriteria implements Criteria {
private Criteria criteria;
private Criteria otherCriteria;
public AndCriteria(Criteria criteria, Criteria otherCriteria) {
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> firstCriteriaPersons = criteria.meetCriteria(persons);
return otherCriteria.meetCriteria(firstCriteriaPersons);
}
}
OrCriteria:满足其中一个就行。分别获取两个条件的结果,然后合并去重。
class OrCriteria implements Criteria {
private Criteria criteria;
private Criteria otherCriteria;
public OrCriteria(Criteria criteria, Criteria otherCriteria) {
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> firstCriteriaPersons = criteria.meetCriteria(persons);
List<Person> otherCriteriaPersons = otherCriteria.meetCriteria(persons);
// 合并结果,避免重复添加同一个对象实例
for (Person otherPerson : otherCriteriaPersons) {
if (!firstCriteriaPersons.contains(otherPerson)) {
firstCriteriaPersons.add(otherPerson);
}
}
return firstCriteriaPersons;
}
}
5. 测试运行
最后我们在主方法里组装这些标准并验证结果。可以看到,通过组合 OrCriteria,我们轻松实现了'男性或单身'的复杂查询。
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("Robert", "Male", "Single"));
persons.add(new Person("John", "Male", "Married"));
persons.add(new Person("Laura", "Female", "Married"));
persons.add(new Person("Diana", "Female", "Single"));
persons.add(new Person("Mike", "Male", "Single"));
persons.add(new Person("Bobby", "Male", "Single"));
Criteria male = new CriteriaMale();
Criteria single = new CriteriaSingle();
Criteria singleOrMale = new OrCriteria(male, single);
System.out.println("-----------------");
System.out.println("All Males:");
for (Person item : male.meetCriteria(persons)) {
System.out.println(item);
}
System.out.println("-----------------");
System.out.println("All Singles:");
for (Person item : single.meetCriteria(persons)) {
System.out.println(item);
}
System.out.println("-----------------");
System.out.println("Singles OR Males:");
List<Person> result = singleOrMale.meetCriteria(persons);
for (Person person : result) {
System.out.println(person);
}
}
总结
通过这种方式,我们将筛选逻辑与业务代码分离开来。如果需要新增一种筛选规则,只需实现 Criteria 接口即可,无需修改现有代码。这种开闭原则的应用,让系统在面对需求变更时更加健壮。

