欢迎光临
我们一直在努力

【从零入门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)
    未经允许不得转载:171主机测评 » 【从零入门23种设计模式07】结构型之过滤器模式(含电商业务场景)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址