目录
1.简介
2.过滤器的实现
2.1.过滤器的角色
2.2.类图
2.3.具体实现
3.过滤器模式的优点
4.过滤器模式的不足
5.适用的场景
过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种结构型设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。说的通俗些就是把一个集合对象根据过滤条件筛选出自己想要的对象。
抽象过滤器角色(AbstractFilter):负责定义过滤器的实现接口,具体的实现还要具体过滤器角色去参与,客户端可以调用抽象过滤器角色中定义好的方法,将客户端的所有请求委派到具体的实现类去,从而让实现类去处理;
具体过滤器角色(ConcreteFilter):该角色负责具体筛选规则的逻辑实现,最后再返回一个过滤后的数据集合,标准的过滤器只对数据做过滤,当然也可以对集合中的数据做某项处理,再将处理后的集合返回;
被过滤的主体角色(Subject):一个软件系统中可以有一个或多个目标角色,在具体过滤器角色中会对指定感兴趣的目标进行处理,以确保后面的数据确实是我想要的。
ICriteria : 抽象过滤器角色,定义了抽象接口doFilter
CCriteriaMale: 具体的过滤器角色,过滤male
CCriteriaFemale: 具体的过滤器角色,过滤female
CCriteriaEducation: 具体的过滤器角色,过滤指定学历的
CCriteriaAboveAge: 具体的过滤器角色,过滤大于某个年龄的
CCriteriaAnd:具体的过滤器角色,实现两个具体的过滤器的逻辑与
CCriteriaOr:具体的过滤器角色,实现两个具体的过滤器的逻辑或
CPerson: 被过滤的主体角色
主体角色和过滤器代码如下:FilterMode.h
#ifndef _FILTER_MODE_H_
#define _FILTER_MODE_H_
#include
#include
//被过滤的实体类
class CPerson
{
public:
explicit CPerson(const std::string& name, const std::string& sex, int age, const std::string& education)
: m_name(name), m_sex(sex), m_age(age), m_education(education) {}
~CPerson() {}
public:
std::string name() const { return m_name; }
std::string sex() const { return m_sex; }
int age() const { return m_age; }
std::string education() const { return m_education; }
std::string toString() const {
return std::string("[name:") + m_name + std::string(";sex:") + m_sex + std::string(";age:") + std::to_string(m_age)
+ std::string(";education:") + m_education + std::string("]");
}
private:
std::string m_name;
std::string m_sex;
int m_age;
std::string m_education;
};
//抽象过滤器
class ICriteria {
public:
virtual std::vector doFilter(const std::vector& persons) = 0;
};
//具体过滤器:过滤male
class CCriteriaMale : public ICriteria
{
public:
std::vector doFilter(const std::vector& persons) override {
std::vector malePersons;
for (auto& it : persons) {
if (0 == it->sex().compare("male")) {
malePersons.push_back(it);
}
}
return malePersons;
}
};
//具体过滤器:过滤female
class CCriteriaFemale : public ICriteria
{
public:
std::vector doFilter(const std::vector& persons) override {
std::vector femalePersons;
for (auto& it : persons) {
if (0 == it->sex().compare("female")) {
femalePersons.push_back(it);
}
}
return femalePersons;
}
};
//具体过滤器:过滤学历
class CCriteriaEducation : public ICriteria
{
public:
explicit CCriteriaEducation(const std::string& education) :m_education(education) {}
public:
std::vector doFilter(const std::vector& persons) override {
std::vector eduPersons;
for (auto& it : persons) {
if (0 == it->education().compare(m_education)) {
eduPersons.push_back(it);
}
}
return eduPersons;
}
private:
std::string m_education;
};
//具体过滤器:过滤年龄
class CCriteriaAboveAge : public ICriteria
{
public:
explicit CCriteriaAboveAge(int age) : m_age(age) {}
public:
std::vector doFilter(const std::vector& persons) override {
std::vector agePersons;
for (auto& it : persons) {
if (it->age() > m_age) {
agePersons.push_back(it);
}
}
return agePersons;
}
private:
int m_age;
};
//具体过滤器:两个过滤器的逻辑与
class CCriteriaAnd : public ICriteria
{
public:
explicit CCriteriaAnd(ICriteria* pCriteria1, ICriteria* pCriteria2)
: m_criteria1(pCriteria1), m_criteria2(pCriteria2) {}
public:
std::vector doFilter(const std::vector& persons) override {
std::vector andPersons = m_criteria1->doFilter(persons);
return m_criteria2->doFilter(andPersons);
}
private:
ICriteria* m_criteria1;
ICriteria* m_criteria2;
};
//具体过滤器:两个过滤器的逻辑或
class CCriteriaOr : public ICriteria
{
public:
explicit CCriteriaOr(ICriteria* pCriteria1, ICriteria* pCriteria2)
: m_criteria1(pCriteria1), m_criteria2(pCriteria2) {}
public:
std::vector doFilter(const std::vector& persons) override {
std::vector orPersons = m_criteria1->doFilter(persons);
std::vector orPersons1 = m_criteria2->doFilter(persons);
for (auto& it : orPersons1) {
if (std::find_if(orPersons.begin(), orPersons.end(),
[=](auto& iter) {return it == iter; }) == orPersons.end()) {
orPersons.push_back(it);
}
}
return orPersons;
}
private:
ICriteria* m_criteria1;
ICriteria* m_criteria2;
};
#endif
使用不同的标准(Criteria)和它们的结合来过滤CPerson对象的列表,测试代码如下:
#include "FilterMode.h"
static void printPerson(const std::string& tip, std::vector& persons) {
qDebug() << tip.data();
for (auto& it : persons) {
qDebug() << it->toString().data();
}
}
void main() {
std::vector vecTemp;
std::vector vecPersons;
vecPersons.push_back(new CPerson("liu bin", "male", 39, "benke"));
vecPersons.push_back(new CPerson("li xiang", "female", 25, "zhuanke"));
vecPersons.push_back(new CPerson("he nan shan", "male", 44, "boshi"));
vecPersons.push_back(new CPerson("san ling", "female", 56, "suoshi"));
vecPersons.push_back(new CPerson("guo dong", "male", 27, "zhuanke"));
vecPersons.push_back(new CPerson("jing gang shan", "female", 32, "suoshi"));
vecPersons.push_back(new CPerson("shan shan", "female", 41, "benke"));
vecPersons.push_back(new CPerson("mei duo", "male", 10, "xiaoxue"));
ICriteria* pMaleCriteria = new CCriteriaMale();
ICriteria* pFemaleCriteria = new CCriteriaFemale();
ICriteria* pAgeCriteria = new CCriteriaAboveAge(26);
ICriteria* pEduCriteria = new CCriteriaEducation("benke");
ICriteria* pAndCriteria = new CCriteriaAnd(pMaleCriteria, pEduCriteria);
ICriteria* pOrCriteria = new CCriteriaOr(pFemaleCriteria, pAgeCriteria);
vecTemp = pMaleCriteria->doFilter(vecPersons);
printPerson("male: ", vecTemp);
vecTemp = pFemaleCriteria->doFilter(vecPersons);
printPerson("female: ", vecTemp);
vecTemp = pAgeCriteria->doFilter(vecPersons);
printPerson("age>26: ", vecTemp);
vecTemp = pEduCriteria->doFilter(vecPersons);
printPerson("benke: ", vecTemp);
vecTemp = pAndCriteria->doFilter(vecPersons);
printPerson("benke and male: ", vecTemp);
vecTemp = pOrCriteria->doFilter(vecPersons);
printPerson("age>26 or female: ", vecTemp);
for (auto& it : vecTemp) {
delete it;
}
delete pMaleCriteria;
delete pFemaleCriteria;
delete pAgeCriteria;
delete pEduCriteria;
delete pAndCriteria;
delete pOrCriteria;
}
输出:
male:
[name:liu bin;sex:male;age:39;education:benke]
[name:he nan shan;sex:male;age:44;education:boshi]
[name:guo dong;sex:male;age:27;education:zhuanke]
[name:mei duo;sex:male;age:10;education:xiaoxue]
female:
[name:li xiang;sex:female;age:25;education:zhuanke]
[name:san ling;sex:female;age:56;education:suoshi]
[name:jing gang shan;sex:female;age:32;education:suoshi]
[name:shan shan;sex:female;age:41;education:benke]
age>26:
[name:liu bin;sex:male;age:39;education:benke]
[name:he nan shan;sex:male;age:44;education:boshi]
[name:san ling;sex:female;age:56;education:suoshi]
[name:guo dong;sex:male;age:27;education:zhuanke]
[name:jing gang shan;sex:female;age:32;education:suoshi]
[name:shan shan;sex:female;age:41;education:benke]
benke:
[name:liu bin;sex:male;age:39;education:benke]
[name:shan shan;sex:female;age:41;education:benke]
benke and male:
[name:liu bin;sex:male;age:39;education:benke]
age>26 or female:
[name:li xiang;sex:female;age:25;education:zhuanke]
[name:san ling;sex:female;age:56;education:suoshi]
[name:jing gang shan;sex:female;age:32;education:suoshi]
[name:shan shan;sex:female;age:41;education:benke]
[name:liu bin;sex:male;age:39;education:benke]
[name:he nan shan;sex:male;age:44;education:boshi]
[name:guo dong;sex:male;age:27;education:zhuanke]
过滤器模式通过提供一种灵活的方式来处理和筛选对象集合,从而提高代码的灵活性和可维护性。
灵活性:过滤器模式充许根据不同的过滤条件对请求进行筛选和传递,这意味看你可以轻松地添加、删除或修改过滤器,而无需修改客户端代码,这使得系统更加灵活,能够适应不同的需求和变化。
可扩展性:由于过滤器模式是可扩展的,你可以在不影响现有代码的情况下添加新的过滤器,这有助于降低代码的耦合度,提高模块化程度,使代码更易于维护和扩展。
复用性:每个过滤器都可以独立地实现其过滤逻辑,这意味着它们是可复用的,你可以在不同的场景下使用相同的过滤器或者将多个过滤器组合在一起以满足更复杂的过滤需求。
解耦:通过将过滤逻辑封装在独立的过滤器中,过滤器模式降低了客户端代码与具体过滤逻辑之间的耦合度,这意味看你可以在不改变客户端代码的情况下更改或替换过滤器,提高了 代码的可维护性。
易于测试:由于每个过滤器都是独立的,你可以单独测试每个过滤器,确保它们按照预期工作,这有助于提高代码的可测讨性和可维护性。
简化复杂逻辑:通过将复杂的筛选逻辑分解为一系列简单的过滤步骤,过滤器模式可以使代码更易于理解和维护,每个过滤器只关注一个特定的筛选条件,从而使代码更加清晰和模块化。
性能问题:当数据集合非常大时,大量的迭代运算,过滤器模式可能会降低程序性能。每次过滤都需要遍历整个数据集合,这可能会降低程序的运行效率。
配置复杂性:当需要组合多个过滤器时,可能需要编写大量的配置代码,这可能会增加代码的复杂性。
1) 数据筛选
在数据处理中,经常需要对大量的数据进行筛选,以满足特定条件。过滤器设计模式可以将这种需求抽象化,通过定义一个过滤器接口,实现不同的筛选逻辑。这种设计模式可以方便地扩展和修改,满足不同的筛选需求。
2) 请求过滤
在Web应用程序中,通常需要对接收到的请求进行筛选和过滤,例如检查用户身份、过滤目的地址请求等。使用过滤设计模式,可以将请求的筛选逻辑封装在过滤器中,对每个请求进行处理。这种设计模式可以提高代码的可维护性和可扩展性。
3) 事件过滤
在事件驱动的系统中,经常需要对事件进行筛选和过滤。例如,在事件总线中,可能需要对事件进行分类和筛选,以便将事件分发给不同的消费者。过滤器设计模式可以将这种需求抽象化,通过定义一个一致的过滤器接口,实现不司的事件筛选逻辑。
4) 日志过滤
在日志记录中,通常需要对日志消息进行筛选和过滤,以满定不同的需求。例如,可能需要根据志级别、日志内容等信息进行筛选和过滤。过滤器设计模式可以将这种需求抽象化通过定义一个日志过滤器接口,实现不同的日志筛选逻辑。
5) 数据流过滤
在数据处理流中,经常需要对数据进行筛选和过滤。例如,在流处理中,可能需要对数据进行分类、去重、转换等操作。过滤器设计模式可以将这种需求抽象化,通过定义一个数据流过滤器接口,实现不同的数据筛选逻辑。这种设计模式可以提高数据处理流的灵活性和可抗展性。