Skip to content

过滤器模式

约 673 字大约 2 分钟

设计模式

2018-05-03

什么是过滤器模式?

Filter(过滤器)模式 是一种结构型设计模式。

它允许使用不同标准过滤一组对象,并通过逻辑操作(AND、OR)组合这些标准。 核心思想是 解耦过滤逻辑与业务代码,使系统更灵活、可扩展。 在 JavaScript 中,通常结合高阶函数(如 filter())实现。

实现 Filter(过滤器)模式

简单实现(函数式风格)

// 过滤器函数
function genderFilter(gender) {
  return persons =>
    persons.filter(p => p.gender === gender)
}

function statusFilter(status) {
  return persons =>
    persons.filter(p => p.maritalStatus === status)
}

// 组合过滤器
const andFilter = (f1, f2) => persons => f2(f1(persons))
function orFilter(f1, f2) {
  return persons =>
    [...new Set([...f1(persons), ...f2(persons)])]
}

// 使用示例
const getSingleFemales = andFilter(
  genderFilter('Female'),
  statusFilter('Single')
)

console.log(getSingleFemales(persons)) // [Alice]

类实现(对象方面)

// 1. 定义数据对象
class Person {
  constructor(name, gender, maritalStatus) {
    this.name = name
    this.gender = gender
    this.maritalStatus = maritalStatus
  }
}

// 2. 定义过滤器接口
class Criteria {
  meetCriteria(persons) {
    throw new Error('必须实现 meetCriteria 方法')
  }
}

// 3. 具体过滤器实现
class GenderCriteria extends Criteria {
  constructor(gender) {
    super()
    this.gender = gender
  }

  meetCriteria(persons) {
    return persons.filter(p => p.gender === this.gender)
  }
}

class MaritalStatusCriteria extends Criteria {
  constructor(status) {
    super()
    this.status = status
  }

  meetCriteria(persons) {
    return persons.filter(p => p.maritalStatus === this.status)
  }
}

// 4. 组合过滤器 (AND/OR)
class AndCriteria extends Criteria {
  constructor(criteria1, criteria2) {
    super()
    this.criteria1 = criteria1
    this.criteria2 = criteria2
  }

  meetCriteria(persons) {
    return this.criteria2.meetCriteria(this.criteria1.meetCriteria(persons))
  }
}

class OrCriteria extends Criteria {
  constructor(criteria1, criteria2) {
    super()
    this.criteria1 = criteria1
    this.criteria2 = criteria2
  }

  meetCriteria(persons) {
    const result1 = this.criteria1.meetCriteria(persons)
    const result2 = this.criteria2.meetCriteria(persons)
    // 合并并去重
    return [...new Set([...result1, ...result2])]
  }
}

// 5. 使用示例
const persons = [
  new Person('Alice', 'Female', 'Single'),
  new Person('Bob', 'Male', 'Single'),
  new Person('Charlie', 'Male', 'Married')
]

// 创建过滤器
const female = new GenderCriteria('Female')
const single = new MaritalStatusCriteria('Single')
const singleFemale = new AndCriteria(female, single)
const maleOrSingle = new OrCriteria(
  new GenderCriteria('Male'),
  single
)

// 应用过滤器
console.log(singleFemale.meetCriteria(persons))
// 输出: [Person{name: 'Alice', ...}]

console.log(maleOrSingle.meetCriteria(persons))
// 输出: [Bob, Charlie, Alice] (男性或单身)

优点

  • 开闭原则:新增过滤标准无需修改已有代码。
  • 解耦:过滤逻辑与业务逻辑分离。
  • 可组合性:通过 AND/OR 轻松组合多个条件。
  • 复用性:过滤器可在多处重复使用。
  • 函数式友好:天然契合 JavaScript 的高阶函数特性。

缺点

  • 性能开销:链式过滤可能需多次遍历数据(大型数据集需优化)。
  • 类膨胀:每个新标准需创建新类(可改用函数式简化)。
  • 过度设计:简单场景下直接使用 Array.filter() 更合适。

适用场景

  • 动态查询条件:如电商产品的多维度筛选(价格、品牌、评分)。
  • 数据报表:按不同业务标准过滤统计信息。
  • 权限系统:组合角色/权限规则过滤用户。
  • API 数据过滤:后端返回数据集,前端按需过滤展示。
  • 复杂条件组合:需要支持 AND/OR/NOT 逻辑的查询。