【从零入门23种设计模式07】结构型之过滤器模式(含电商业务场景)
·
作者:逆境不可逃
希望大家能多多关注点赞收藏一键三连!!!
你的支持是我创作的动力!!!
一、过滤器模式核心概念
过滤器模式(也叫标准模式 / Criteria Pattern)是一种行为型设计模式,核心思想是:
- 定义多个「过滤规则(过滤器)」,可以单独使用或组合使用(与 / 或 / 非);
- 对一组对象进行筛选,最终得到符合条件的对象集合;
- 优点:规则解耦(新增 / 修改过滤规则不影响原有代码)、规则可复用、支持灵活组合。
简单理解:你网购时筛选商品 ——“价格 < 500 元”“包邮”“好评率 > 95%”,每个条件就是一个过滤器,组合起来就是过滤器模式的典型应用。
二、核心结构
过滤器模式通常包含 4 个核心角色:
- 目标对象(Entity):被过滤的对象(如商品、用户、订单);
- 过滤器接口(Filter/Criteria):定义过滤方法(如
List<T> filter(List<T> list)); - 具体过滤器(ConcreteFilter):实现接口,定义具体的过滤规则;
- 组合过滤器(CompositeFilter):组合多个过滤器(如 “与 / 或” 逻辑)。
三、实际场景:电商商品筛选
场景描述
假设你开发一个电商系统,需要实现商品筛选功能:
- 筛选条件:价格区间、是否包邮、是否为新品(上架时间 < 7 天);
- 支持组合筛选(如 “价格 < 500 元 且 包邮”“新品 或 包邮”)。
步骤 1:定义目标对象(商品)
import java.time.LocalDateTime;
// 商品实体(被过滤的对象)
public class Product {
private String name; // 商品名称
private double price; // 价格
private boolean freeShip; // 是否包邮
private LocalDateTime createTime; // 上架时间
// 构造器、getter/setter(省略,实际开发需补充)
public Product(String name, double price, boolean freeShip, LocalDateTime createTime) {
this.name = name;
this.price = price;
this.freeShip = freeShip;
this.createTime = createTime;
}
// 重写toString,方便打印结果
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", price=" + price +
", freeShip=" + freeShip +
", createTime=" + createTime +
'}';
}
// getter方法(必须,过滤器需要读取属性)
public double getPrice() { return price; }
public boolean isFreeShip() { return freeShip; }
public LocalDateTime getCreateTime() { return createTime; }
public String getName() { return name; }
}
步骤 2:定义过滤器接口
import java.util.List;
// 过滤器接口:定义统一的过滤方法
public interface ProductFilter {
// 入参:待过滤的商品列表;返回值:符合条件的商品列表
List<Product> filter(List<Product> products);
}
步骤 3:实现具体过滤器(单一规则)
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
// 过滤器1:价格过滤(价格<指定值)
public class PriceFilter implements ProductFilter {
private double maxPrice; // 最大价格阈值
public PriceFilter(double maxPrice) {
this.maxPrice = maxPrice;
}
@Override
public List<Product> filter(List<Product> products) {
// 过滤逻辑:价格 < maxPrice
return products.stream()
.filter(p -> p.getPrice() < maxPrice)
.collect(Collectors.toList());
}
}
// 过滤器2:包邮过滤
public class FreeShipFilter implements ProductFilter {
@Override
public List<Product> filter(List<Product> products) {
// 过滤逻辑:包邮(freeShip=true)
return products.stream()
.filter(Product::isFreeShip)
.collect(Collectors.toList());
}
}
// 过滤器3:新品过滤(上架时间<7天)
public class NewProductFilter implements ProductFilter {
@Override
public List<Product> filter(List<Product> products) {
LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7);
// 过滤逻辑:上架时间 > 7天前(即近7天上架)
return products.stream()
.filter(p -> p.getCreateTime().isAfter(sevenDaysAgo))
.collect(Collectors.toList());
}
}
步骤 4:实现组合过滤器(多规则组合)
import java.util.List;
import java.util.stream.Collectors;
// 组合过滤器:实现“与”逻辑(同时满足多个过滤器)
public class AndFilter implements ProductFilter {
private ProductFilter[] filters; // 待组合的过滤器数组
public AndFilter(ProductFilter... filters) {
this.filters = filters;
}
@Override
public List<Product> filter(List<Product> products) {
List<Product> result = products;
// 依次应用所有过滤器(只有同时满足所有规则才会保留)
for (ProductFilter filter : filters) {
result = filter.filter(result);
if (result.isEmpty()) break; // 无数据时提前终止
}
return result;
}
}
// 组合过滤器:实现“或”逻辑(满足任意一个过滤器)
public class OrFilter implements ProductFilter {
private ProductFilter[] filters;
public OrFilter(ProductFilter... filters) {
this.filters = filters;
}
@Override
public List<Product> filter(List<Product> products) {
// 只要商品满足任意一个过滤器的条件,就保留
return products.stream()
.filter(product -> {
for (ProductFilter filter : filters) {
// 检查当前商品是否符合某个过滤器的条件
List<Product> filtered = filter.filter(List.of(product));
if (!filtered.isEmpty()) {
return true;
}
}
return false;
})
.collect(Collectors.toList());
}
}
// 扩展:非过滤器(取反逻辑)
public class NotFilter implements ProductFilter {
private ProductFilter filter;
public NotFilter(ProductFilter filter) {
this.filter = filter;
}
@Override
public List<Product> filter(List<Product> products) {
// 先获取符合条件的商品,再取反
List<Product> matched = filter.filter(products);
return products.stream()
.filter(p -> !matched.contains(p))
.collect(Collectors.toList());
}
}
五、测试用代码
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class FilterPatternTest {
public static void main(String[] args) {
// 1. 准备测试数据:创建5个商品
List<Product> productList = new ArrayList<>();
productList.add(new Product("手机", 4999.0, false, LocalDateTime.now().minusDays(2))); // 新品、不包邮、高价
productList.add(new Product("耳机", 299.0, true, LocalDateTime.now().minusDays(10))); // 包邮、非新品、低价
productList.add(new Product("充电宝", 89.0, true, LocalDateTime.now().minusDays(3))); // 包邮、新品、低价
productList.add(new Product("键盘", 399.0, false, LocalDateTime.now().minusDays(1))); // 新品、不包邮、低价
productList.add(new Product("鼠标", 199.0, false, LocalDateTime.now().minusDays(15))); // 非新品、不包邮、低价
// 2. 定义单个过滤器
ProductFilter priceFilter = new PriceFilter(500.0); // 价格<500元
ProductFilter freeShipFilter = new FreeShipFilter(); // 包邮
ProductFilter newProductFilter = new NewProductFilter(); // 新品
// 3. 测试单个过滤规则
System.out.println("===== 价格<500元的商品 =====");
priceFilter.filter(productList).forEach(System.out::println);
// 4. 测试组合过滤:价格<500元 且 包邮
System.out.println("\n===== 价格<500元 且 包邮的商品 =====");
ProductFilter andFilter = new AndFilter(priceFilter, freeShipFilter);
andFilter.filter(productList).forEach(System.out::println);
// 5. 测试组合过滤:新品 或 包邮
System.out.println("\n===== 新品 或 包邮的商品 =====");
ProductFilter orFilter = new OrFilter(newProductFilter, freeShipFilter);
orFilter.filter(productList).forEach(System.out::println);
// 6. 测试非过滤:不包邮的商品
System.out.println("\n===== 不包邮的商品 =====");
ProductFilter notFilter = new NotFilter(freeShipFilter);
notFilter.filter(productList).forEach(System.out::println);
}
}
六、测试输出结果
===== 价格<500元的商品 =====
Product{name='耳机', price=299.0, freeShip=true, createTime=2026-02-14T10:00:00}
Product{name='充电宝', price=89.0, freeShip=true, createTime=2026-02-21T10:00:00}
Product{name='键盘', price=399.0, freeShip=false, createTime=2026-02-23T10:00:00}
Product{name='鼠标', price=199.0, freeShip=false, createTime=2026-02-09T10:00:00}
===== 价格<500元 且 包邮的商品 =====
Product{name='耳机', price=299.0, freeShip=true, createTime=2026-02-14T10:00:00}
Product{name='充电宝', price=89.0, freeShip=true, createTime=2026-02-21T10:00:00}
===== 新品 或 包邮的商品 =====
Product{name='手机', price=4999.0, freeShip=false, createTime=2026-02-22T10:00:00}
Product{name='耳机', price=299.0, freeShip=true, createTime=2026-02-14T10:00:00}
Product{name='充电宝', price=89.0, freeShip=true, createTime=2026-02-21T10:00:00}
Product{name='键盘', price=399.0, freeShip=false, createTime=2026-02-23T10:00:00}
===== 不包邮的商品 =====
Product{name='手机', price=4999.0, freeShip=false, createTime=2026-02-22T10:00:00}
Product{name='键盘', price=399.0, freeShip=false, createTime=2026-02-23T10:00:00}
Product{name='鼠标', price=199.0, freeShip=false, createTime=2026-02-09T10:00:00}
七、实际应用扩展建议
- 性能优化:
- 若数据量较大,可将
Stream替换为普通循环(减少流式 API 的开销); - 对高频过滤条件,可提前缓存过滤结果(如缓存 “包邮商品列表”)。
- 若数据量较大,可将
- 规则扩展:
- 新增过滤规则时,只需实现
ProductFilter接口(如BrandFilter按品牌过滤、ScoreFilter按好评率过滤),无需修改原有代码,符合「开闭原则」; - 支持更复杂的组合(如
AndFilter(OrFilter(a,b), c)→ “(a 或 b) 且 c”)。
- 新增过滤规则时,只需实现
- 实际业务场景:
- 后台管理系统的 “用户筛选”(按角色、注册时间、活跃度);
- 日志系统的 “日志过滤”(按级别、模块、时间);
- 订单系统的 “订单筛选”(按状态、金额、支付方式)。
总结
- 过滤器模式的核心是将过滤规则抽象为独立组件,实现规则与业务逻辑解耦;
- 通过「单一过滤器 + 组合过滤器」,可灵活实现任意复杂的筛选逻辑,且新增规则成本极低;
- 在 Java 中结合 Stream API 能简化过滤代码,适合电商、后台管理等需要多条件筛选的场景。
扩展
扩展 1:动态配置过滤规则(前端传参场景)
实际开发中,过滤条件往往由前端用户选择(如价格区间、是否包邮、新品等),需要动态组装过滤器,而非硬编码。
步骤 1:定义过滤条件 DTO(接收前端参数)
import java.time.LocalDateTime;
// 前端传入的过滤条件封装类
public class ProductFilterDTO {
private Double minPrice; // 最低价格(可选)
private Double maxPrice; // 最高价格(可选)
private Boolean freeShip; // 是否包邮(可选,null表示不筛选)
private Boolean isNew; // 是否新品(可选,null表示不筛选)
// 构造器、getter/setter
public ProductFilterDTO(Double minPrice, Double maxPrice, Boolean freeShip, Boolean isNew) {
this.minPrice = minPrice;
this.maxPrice = maxPrice;
this.freeShip = freeShip;
this.isNew = isNew;
}
// getter方法
public Double getMinPrice() { return minPrice; }
public Double getMaxPrice() { return maxPrice; }
public Boolean getFreeShip() { return freeShip; }
public Boolean getIsNew() { return isNew; }
}
步骤 2:实现动态过滤器组装工具类
import java.util.ArrayList;
import java.util.List;
// 动态组装过滤器的工具类
public class FilterAssembler {
/**
* 根据前端DTO动态组装过滤器(只组装非空的过滤条件)
*/
public static ProductFilter assembleFilter(ProductFilterDTO dto) {
List<ProductFilter> filterList = new ArrayList<>();
// 1. 价格过滤(支持区间:minPrice <= 价格 <= maxPrice)
if (dto.getMinPrice() != null || dto.getMaxPrice() != null) {
filterList.add(new PriceRangeFilter(dto.getMinPrice(), dto.getMaxPrice()));
}
// 2. 包邮过滤(仅当freeShip不为null时添加)
if (dto.getFreeShip() != null) {
filterList.add(new FreeShipFilter(dto.getFreeShip()));
}
// 3. 新品过滤(仅当isNew不为null时添加)
if (dto.getIsNew() != null) {
filterList.add(new NewProductFilter(dto.getIsNew()));
}
// 无过滤条件时,返回“全部通过”的过滤器
if (filterList.isEmpty()) {
return products -> products;
}
// 多个条件默认按“与”逻辑组合(同时满足)
return new AndFilter(filterList.toArray(new ProductFilter[0]));
}
// 扩展:价格区间过滤器(替代原单一价格过滤器)
static class PriceRangeFilter implements ProductFilter {
private Double minPrice;
private Double maxPrice;
public PriceRangeFilter(Double minPrice, Double maxPrice) {
this.minPrice = minPrice;
this.maxPrice = maxPrice;
}
@Override
public List<Product> filter(List<Product> products) {
return products.stream()
.filter(p -> {
boolean minOk = (minPrice == null) || p.getPrice() >= minPrice;
boolean maxOk = (maxPrice == null) || p.getPrice() <= maxPrice;
return minOk && maxOk;
})
.collect(Collectors.toList());
}
}
// 扩展:可配置的包邮过滤器(支持“包邮/不包邮”)
static class FreeShipFilter implements ProductFilter {
private boolean expectFreeShip;
public FreeShipFilter(boolean expectFreeShip) {
this.expectFreeShip = expectFreeShip;
}
@Override
public List<Product> filter(List<Product> products) {
return products.stream()
.filter(p -> p.isFreeShip() == expectFreeShip)
.collect(Collectors.toList());
}
}
// 扩展:可配置的新品过滤器(支持“是新品/不是新品”)
static class NewProductFilter implements ProductFilter {
private boolean expectNew;
public NewProductFilter(boolean expectNew) {
this.expectNew = expectNew;
}
@Override
public List<Product> filter(List<Product> products) {
LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7);
return products.stream()
.filter(p -> {
boolean isNew = p.getCreateTime().isAfter(sevenDaysAgo);
return isNew == expectNew;
})
.collect(Collectors.toList());
}
}
}
步骤 3:测试动态组装过滤器
public class DynamicFilterTest {
public static void main(String[] args) {
// 1. 复用之前的商品列表(productList)
List<Product> productList = initProductList();
// 2. 模拟前端传入的条件:价格100-400元 且 包邮
ProductFilterDTO dto = new ProductFilterDTO(100.0, 400.0, true, null);
ProductFilter dynamicFilter = FilterAssembler.assembleFilter(dto);
// 3. 执行过滤
System.out.println("===== 动态筛选:价格100-400元 且 包邮 =====");
dynamicFilter.filter(productList).forEach(System.out::println);
// 4. 模拟前端传入的条件:非新品 且 不包邮
ProductFilterDTO dto2 = new ProductFilterDTO(null, null, false, false);
ProductFilter dynamicFilter2 = FilterAssembler.assembleFilter(dto2);
System.out.println("\n===== 动态筛选:非新品 且 不包邮 =====");
dynamicFilter2.filter(productList).forEach(System.out::println);
}
// 初始化商品列表(复用之前的测试数据)
private static List<Product> initProductList() {
List<Product> productList = new ArrayList<>();
productList.add(new Product("手机", 4999.0, false, LocalDateTime.now().minusDays(2)));
productList.add(new Product("耳机", 299.0, true, LocalDateTime.now().minusDays(10)));
productList.add(new Product("充电宝", 89.0, true, LocalDateTime.now().minusDays(3)));
productList.add(new Product("键盘", 399.0, false, LocalDateTime.now().minusDays(1)));
productList.add(new Product("鼠标", 199.0, false, LocalDateTime.now().minusDays(15)));
return productList;
}
}
输出结果
===== 动态筛选:价格100-400元 且 包邮 =====
Product{name='耳机', price=299.0, freeShip=true, createTime=2026-02-14T10:00:00}
===== 动态筛选:非新品 且 不包邮 =====
Product{name='鼠标', price=199.0, freeShip=false, createTime=2026-02-09T10:00:00}
扩展 2:高性能批量过滤(大数据量场景)
当商品列表数据量达到万级 / 十万级时,Stream API 的开销会增大,需优化为普通循环 + 提前终止 + 并行处理。
高性能过滤器实现
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
// 高性能批量过滤器(适配大数据量)
public class HighPerformanceFilter implements ProductFilter {
private ProductFilter[] filters;
// 并行处理的线程池(复用JDK默认的ForkJoinPool)
private static final ForkJoinPool POOL = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
public HighPerformanceFilter(ProductFilter... filters) {
this.filters = filters;
}
@Override
public List<Product> filter(List<Product> products) {
List<Product> result = new ArrayList<>(products.size());
// 1. 大数据量时启用并行处理(阈值可根据业务调整,这里设为1000)
if (products.size() > 1000) {
POOL.submit(() -> {
products.parallelStream().forEach(product -> {
if (matchAllFilters(product)) {
synchronized (result) { // 线程安全添加
result.add(product);
}
}
});
}).join();
} else {
// 2. 小数据量用普通循环(减少并行开销)
for (Product product : products) {
if (matchAllFilters(product)) {
result.add(product);
}
}
}
return result;
}
/**
* 检查商品是否匹配所有过滤器(提前终止:只要一个不匹配就返回false)
*/
private boolean matchAllFilters(Product product) {
for (ProductFilter filter : filters) {
// 单个商品过滤,避免创建List,提升性能
if (!filter.filter(List.of(product)).isEmpty()) {
continue;
}
return false; // 不匹配,提前终止
}
return true;
}
// 测试高性能过滤
public static void main(String[] args) {
// 1. 构造10000个测试商品(模拟大数据量)
List<Product> bigProductList = new ArrayList<>(10000);
LocalDateTime now = LocalDateTime.now();
for (int i = 0; i < 10000; i++) {
bigProductList.add(new Product(
"商品" + i,
100 + i % 500, // 价格100-600
i % 3 == 0, // 每3个商品一个包邮
now.minusDays(i % 10) // 上架时间0-9天前
));
}
// 2. 定义过滤条件:价格<500 且 包邮 且 新品
ProductFilter priceFilter = new FilterAssembler.PriceRangeFilter(null, 500.0);
ProductFilter freeShipFilter = new FilterAssembler.FreeShipFilter(true);
ProductFilter newFilter = new FilterAssembler.NewProductFilter(true);
// 3. 高性能过滤
HighPerformanceFilter highPerfFilter = new HighPerformanceFilter(priceFilter, freeShipFilter, newFilter);
long start = System.currentTimeMillis();
List<Product> result = highPerfFilter.filter(bigProductList);
long end = System.currentTimeMillis();
System.out.println("筛选结果数量:" + result.size());
System.out.println("耗时:" + (end - start) + "ms");
}
}
核心优化点
- 提前终止:
matchAllFilters方法中,只要商品不匹配一个过滤器,立即返回 false,避免无效计算; - 分场景处理:小数据量用普通循环,大数据量用并行流,平衡并行开销;
- 减少对象创建:单个商品过滤时,避免频繁创建 List,提升内存利用率;
- 线程池复用:使用 ForkJoinPool 适配并行处理,避免重复创建线程。
补充总结
- 动态过滤:通过 DTO 接收前端参数,动态组装过滤器,适配业务中 “用户自定义筛选条件” 的场景,符合开闭原则;
- 高性能过滤:针对大数据量优化,通过 “提前终止 + 分场景处理 + 并行计算” 降低耗时,适合电商商品列表、日志筛选等数据量大的场景;
- 扩展建议:实际项目中可结合 Spring 的
@Component将过滤器注册为 Bean,通过配置文件管理过滤规则,进一步降低耦合。

更多推荐




所有评论(0)