设计模式之过滤器模式

目录

1.简介

2.过滤器的实现

2.1.过滤器的角色

2.2.类图

2.3.具体实现

3.过滤器模式的优点

4.过滤器模式的不足

5.适用的场景


1.简介

过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种结构型设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。说的通俗些就是把一个集合对象根据过滤条件筛选出自己想要的对象。

2.过滤器的实现

2.1.过滤器的角色

抽象过滤器角色(AbstractFilter):负责定义过滤器的实现接口,具体的实现还要具体过滤器角色去参与,客户端可以调用抽象过滤器角色中定义好的方法,将客户端的所有请求委派到具体的实现类去,从而让实现类去处理;
具体过滤器角色(ConcreteFilter):该角色负责具体筛选规则的逻辑实现,最后再返回一个过滤后的数据集合,标准的过滤器只对数据做过滤,当然也可以对集合中的数据做某项处理,再将处理后的集合返回;
被过滤的主体角色(Subject):一个软件系统中可以有一个或多个目标角色,在具体过滤器角色中会对指定感兴趣的目标进行处理,以确保后面的数据确实是我想要的。

2.2.类图

3549e393ce924a42a9fdd282b45c6ffc.png

ICriteria : 抽象过滤器角色,定义了抽象接口doFilter

CCriteriaMale: 具体的过滤器角色,过滤male

CCriteriaFemale: 具体的过滤器角色,过滤female

CCriteriaEducation: 具体的过滤器角色,过滤指定学历的

CCriteriaAboveAge: 具体的过滤器角色,过滤大于某个年龄的

CCriteriaAnd:具体的过滤器角色,实现两个具体的过滤器的逻辑与

CCriteriaOr:具体的过滤器角色,实现两个具体的过滤器的逻辑或

CPerson: 被过滤的主体角色

2.3.具体实现

主体角色和过滤器代码如下:FilterMode.h

#ifndef _FILTER_MODE_H_
#define _FILTER_MODE_H_
#include <string>
#include <vector>//被过滤的实体类
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<CPerson*>  doFilter(const std::vector<CPerson*>& persons) = 0;
};//具体过滤器:过滤male
class CCriteriaMale : public ICriteria
{
public:std::vector<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {std::vector<CPerson*> 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<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {std::vector<CPerson*> 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<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {std::vector<CPerson*> 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<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {std::vector<CPerson*> 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<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {std::vector<CPerson*> 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<CPerson*>  doFilter(const std::vector<CPerson*>& persons) override {std::vector<CPerson*> orPersons = m_criteria1->doFilter(persons);std::vector<CPerson*> 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<CPerson*>& persons) {qDebug() << tip.data();for (auto& it : persons) {qDebug() << it->toString().data();}
}
void main() {std::vector<CPerson*> vecTemp;std::vector<CPerson*> 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]

3.过滤器模式的优点

过滤器模式通过提供一种灵活的方式来处理和筛选对象集合,从而提高代码的灵活性和可维护性。

灵活性:过滤器模式充许根据不同的过滤条件对请求进行筛选和传递,这意味看你可以轻松地添加、删除或修改过滤器,而无需修改客户端代码,这使得系统更加灵活,能够适应不同的需求和变化。

可扩展性:由于过滤器模式是可扩展的,你可以在不影响现有代码的情况下添加新的过滤器,这有助于降低代码的耦合度,提高模块化程度,使代码更易于维护和扩展。

复用性:每个过滤器都可以独立地实现其过滤逻辑,这意味着它们是可复用的,你可以在不同的场景下使用相同的过滤器或者将多个过滤器组合在一起以满足更复杂的过滤需求。

解耦:通过将过滤逻辑封装在独立的过滤器中,过滤器模式降低了客户端代码与具体过滤逻辑之间的耦合度,这意味看你可以在不改变客户端代码的情况下更改或替换过滤器,提高了  代码的可维护性。

易于测试:由于每个过滤器都是独立的,你可以单独测试每个过滤器,确保它们按照预期工作,这有助于提高代码的可测讨性和可维护性。

简化复杂逻辑:通过将复杂的筛选逻辑分解为一系列简单的过滤步骤,过滤器模式可以使代码更易于理解和维护,每个过滤器只关注一个特定的筛选条件,从而使代码更加清晰和模块化。

4.过滤器模式的不足

性能问题:当数据集合非常大时,大量的迭代运算,过滤器模式可能会降低程序性能。每次过滤都需要遍历整个数据集合,这可能会降低程序的运行效率。

配置复杂性:当需要组合多个过滤器时,可能需要编写大量的配置代码,这可能会增加代码的复杂性。

5.适用的场景

1) 数据筛选

在数据处理中,经常需要对大量的数据进行筛选,以满足特定条件。过滤器设计模式可以将这种需求抽象化,通过定义一个过滤器接口,实现不同的筛选逻辑。这种设计模式可以方便地扩展和修改,满足不同的筛选需求。

2) 请求过滤

在Web应用程序中,通常需要对接收到的请求进行筛选和过滤,例如检查用户身份、过滤目的地址请求等。使用过滤设计模式,可以将请求的筛选逻辑封装在过滤器中,对每个请求进行处理。这种设计模式可以提高代码的可维护性和可扩展性。

3) 事件过滤

在事件驱动的系统中,经常需要对事件进行筛选和过滤。例如,在事件总线中,可能需要对事件进行分类和筛选,以便将事件分发给不同的消费者。过滤器设计模式可以将这种需求抽象化,通过定义一个一致的过滤器接口,实现不司的事件筛选逻辑。

4) 日志过滤

在日志记录中,通常需要对日志消息进行筛选和过滤,以满定不同的需求。例如,可能需要根据志级别、日志内容等信息进行筛选和过滤。过滤器设计模式可以将这种需求抽象化通过定义一个日志过滤器接口,实现不同的日志筛选逻辑。

5) 数据流过滤

在数据处理流中,经常需要对数据进行筛选和过滤。例如,在流处理中,可能需要对数据进行分类、去重、转换等操作。过滤器设计模式可以将这种需求抽象化,通过定义一个数据流过滤器接口,实现不同的数据筛选逻辑。这种设计模式可以提高数据处理流的灵活性和可抗展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/324413.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基本语法

第一章 Java基本语法 1. Java程序剖析1.1 Java代码的基本格式1.2 包、import1.3 类1.4 main()方法1.5 方法1.6 标识符1.7 关键字1.8 修饰符1.9 程序块1.10 语句1.11 Java代码的注释 2. 常量与变量2.1 常量2.2 变量2.2 变量的分类2.2.1 成员变量2.2.2 局部变…

初识Winform

什么是winform&#xff1f; WinForms&#xff08;Windows Forms&#xff09;是Microsoft .NET框架中的一个用户界面&#xff08;UI&#xff09;技术&#xff0c;用于创建Windows应用程序。它提供了一组用于构建图形用户界面的类和控件&#xff0c;以及与用户交互的事件模型。 …

案例094:基于微信小程序的图书馆自习室座位预约管理系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

Netty初探:掌握高性能网络通信框架,提升Java网络编程技能

Netty初探 NIO 的类库和 API 繁杂 &#xff0c; 使用麻烦&#xff1a; 需要熟练掌握Selector、 ServerSocketChannel、SocketChannel、 ByteBuffer等。 开发工作量和难度都非常大&#xff1a; 例如客户端面临断线重连、 网络闪断、心跳处理、半包读写、 网络拥塞和异常流的处…

【2024最新版】Win11基础配置操作(磁盘分区、修改各种默认存储位置、安装软件操作)【释放C盘空间】

文章目录 一、硬盘分区0. 磁盘管理1. 压缩卷2. 新建简单卷向导 二、修改默认存储位置1. 保持新内容的地方a. 位置b. 操作 2. 快速访问六件套a. 位置b. 操作 三、安装软件0. 应用商店设置a. 设置中心b. 修改下载设置 1. 微信电脑版设置a. 下载b. 安装c. 聊天记录迁移与备份d. 存…

JavaWeb基础(3)-会话技术(cookie和session),过滤器(Filter),监听器(Listener)

JavaWeb基础&#xff08;3&#xff09;-会话技术(cookie和session)&#xff0c;过滤器(Filter)&#xff0c;监听器(Listener) 文章目录 JavaWeb基础&#xff08;3&#xff09;-会话技术(cookie和session)&#xff0c;过滤器(Filter)&#xff0c;监听器(Listener)8 会话技术(Coo…

遥感影像-语义分割数据集:2021年昇腾杯复赛数据集详细介绍及训练样本处理流程

原始数据集详情 简介&#xff1a;细粒度语义分割赛道依据现有的遥感地物分类要求&#xff0c; 结合现有的地物分类实际需求&#xff0c;参照地理国情监测、 “三调”等既有地物分类标准&#xff0c;依据遥感地物“所见即所得”原则&#xff0c; 设计地物要素分类体系&#xff…

【Linux Shell】6. echo 命令

文章目录 【 1. 显示普通字符串 】【 2. 显示转义字符 】【 3. 显示变量 】【 4. 显示换行 】【 5. 显示不换行 】【 6. 显示命令执行结果 】 Shell 的 echo 指令用于字符串的输出。命令格式&#xff1a; echo string【 1. 显示普通字符串 】 #!/bin/bashecho "It is a …

Maven初学Day1

1.Maven是什么&#xff1f; 是一个构建工具&#xff0c;可以自动化构建过程、任务。是一个项目模型 2.作为构建工具有什么特点 1.跨平台&#xff0c;可以在多个操作系统上使用 2.对外提供一致的操作接口 3.Maven官网 https://maven.apache.org/download.cgi 4.安装步骤 …

P11 FFmpe时间基和时间戳

前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_C…

C++多态性——(5)运算符重载(第一节)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 晚上想想千条路&#xff0c;早上醒来走…

Linux 进程(十) 进程替换

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec*函数以执行另一个程序。当进程调用一种exec*函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec*并不创建新进程,所以调用exec*前…