设计模式笔记 – 过滤器模式
过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。
介绍
- 意图: 对同一组对象能够以不同过滤条件筛选出来
- 主要解决: 能够以不同条件或条件的组合筛选对象
- 何时使用: 一组对象需要根据属性作筛选时
- 如何解决: 使用过滤器类进行筛选
- 关键代码:
- 优点: 能使用不同过滤器的组合方便的筛选对象
- 缺点: 过滤器依赖对象的结构,对象属性变化时过滤器也需要变化,如示例中的婚姻状况增加了一种"离异",则需要增加或修改过滤器
- 应用实例: 1、对用户信息根据不同条件如性别、婚姻状况筛选,2、对车辆根据根据不同条件如颜色、款式筛选
- 使用场景: 过滤标准较多,且分散。
- 注意事项: 过滤器应该尽量简单,复杂的过滤器应使用多个简单过滤器组合得到,这样当对象属性变化时,过滤器的改动能尽量小
示例
我们将创建一个 Person 对象、Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列表。CriteriaPatternDemo,我们的演示类使用 Criteria 对象,基于各种标准和它们的结合来过滤 Person 对象的列表。
Java 实现
创建一个类,在该类上应用标准
public class Person {
private String name;
private String gender;
private String meritalStatus;
public Person(String name, String gender, String meritalStatus) {
this.name = name;
this.gender = gender;
this.meritalStatus = meritalStatus;
}
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public String getMeritalStatus() {
return meritalStatus;
}
}
为标准(Criteria)创建一个接口
import java.util.List;
public interface Criteria {
public List<Person> meetCriteria(List<Person> persons);
}
创建实现了Criteria接口的实体类
import java.util.ArrayList;
import java.util.List;
public class CriteriaMale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> malePersons = new ArrayList<Person>();
for (Person person : persons) {
if (person.getGender().equalsIgnoreCase("MALE")) {
malePerson.add(person);
}
}
return malePersons;
}
}
import java.util.ArrayList;
import java.util.List;
public class CriteriaFemale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> femalePersons = new ArrayList<Person>();
for (Person person : persons) {
if (person.getGender().equalsIgnoreCase("FEMALE")) {
femalePerson.add(person);
}
}
return femalePersons;
}
}
import java.util.ArrayList;
import java.util.List;
public class CriteriaSingle implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> singlePersons = new ArrayList<Person>();
for (Person person : persons) {
if (person.getMaritalStatus().equalsIgnoreCase("SINGLE")) {
singlePersons.add(person);
}
}
return singlePersons;
}
}
import java.util.List;
public 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);
}
}
import java.util.List;
public class OrCriteria 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);
List<Person> otherCriteriaPersons = otherCriteria.meetCriteria(persons);
for (Person person : otherCriteriaPersons) {
if (!firstCriteriaPersons.contains(person)){
firstCriteriaPersons.add(person);
}
}
return firstCriteriaPersons
}
}
使用不同的标准(Criteria)和它们的结合来过滤Person对象的列表
import java.util.ArrayList;
import java.util.List;
public class CriteriaPatternDemo {
public static void main(String[] args) {
List<Person> persons = new ArrayList<Person>();
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 female = new CriteriaFemale();
Criteria single = new CriteriaSingle();
Criteria singleMale = new AndCriteria(single, male);
Criteria singleOrFemale = new OrCriteria(single, female);
System.out.println("Males: ");
printPersons(male.meetCriteria(persons));
System.out.println("\nFemales: ");
printPersons(female.meetCriteria(persons));
System.out.println("\nSingle Males: ");
printPersons(singleMale.meetCriteria(persons));
System.out.println("\nSingle Or Females: ");
printPersons(singleOrFemale.meetCriteria(persons));
}
public static void printPersons(List<Person> persons){
for (Person person : persons) {
System.out.println("Person : [ Name : " + person.getName()
+", Gender : " + person.getGender()
+", Marital Status : " + person.getMaritalStatus()
+" ]");
}
}
}
Python 实现
import abc
class Person(object):
def __init__(self, name, gender, marital_status):
self.name = name
self.gender = gender
self.marital_status = marital_status
def get_name(self) -> str:
return self.name
def get_gender(self) -> str:
return self.gender
def get_marital_status(self) -> str:
return self.marital_status
class Criteria(abc.ABC):
@abc.abstractmethod
def meet_criteria(self, persons) -> [Person]: ...
class CriteriaMale(Criteria):
def meet_criteria(self, persons):
male_person = []
for person in persons:
if person.get_gender().upper() == "MALE":
male_person.append(person)
return male_person
class CriteriaFemale(Criteria):
def meet_criteria(self, persons):
female_person = []
for person in persons:
if person.get_gender().upper() == "FEMALE":
female_person.append(person)
return female_person
class CriteriaSingle(Criteria):
def meet_criteria(self, persons):
single_person = []
for person in persons:
if person.get_marital_status().upper() == "SINGLE":
single_person.append(person)
return single_person
class AndCriteria(Criteria):
def __init__(self, criteria, other_criteria):
self.criteria = criteria
self.other_criteria = other_criteria
def meet_criteria(self, persons):
first_criteria_persons = self.criteria.meet_criteria(persons)
return self.other_criteria.meet_criteria(first_criteria_persons)
class OrCriteria(Criteria):
def __init__(self, criteria, other_criteria):
self.criteria = criteria
self.other_criteria = other_criteria
def meet_criteria(self, persons):
first_criteria_persons = self.criteria.meet_criteria(persons)
other_criteria_persons = self.other_criteria.meet_criteria(persons)
for person in other_criteria_persons:
if person not in first_criteria_persons:
first_criteria_persons.append(person)
return first_criteria_persons
def print_persons(persons):
for person in persons:
print(f"Person: [Name: {person.get_name()}, "
f"Gender: {person.get_gender()}, "
f"Marital Status: {person.get_marital_status()}]")
if __name__ == "__main__":
persons = []
persons.append(Person("Robert", "Male", "Single"))
persons.append(Person("John", "Male", "Married"))
persons.append(Person("Laura", "Female", "Married"))
persons.append(Person("Diana", "Female", "Single"))
persons.append(Person("Mike", "Male", "Single"))
persons.append(Person("Bobby", "Male", "Single"))
male = CriteriaMale()
female = CriteriaFemale()
single = CriteriaSingle()
single_male = AndCriteria(single, male)
single_or_female = OrCriteria(single, female)
print("Male: ")
print_persons(male.meet_criteria(persons))
print("Female: ")
print_persons(female.meet_criteria(persons))
print("Single Males: ")
print_persons(single_male.meet_criteria(persons))
print("Single Or Females: ")
print_persons(single_or_female.meet_criteria(persons))