You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SOLID依赖倒置原则:工具函数应定义接口还是直接使用具体实现?

方案选型结论与分析

先明确核心需求前提

你的核心诉求是将判断逻辑封装为可跨类复用的工具函数,我们基于这个前提对三个方案逐一分析:


1. 私有方法实现方案:不适用当前场景

export class UserRepository {
  constructor (
    private readonly database: DatabaseProtocol
  ) {}

  async findUserByEmail (data: Record<string, any>): Promise<IUser | null> {
    const userCollection = this.database.collection('users')

    if (this.isEmpty(data)) return null

    const user = await userCollection.findOne({ email: data.email })

    return user
  }

  isEmpty (data: Record<string, any>): boolean {
    return Object.keys(data).length === 0
  }
}

这个方案只能在当前UserRepository类内部使用isEmpty方法,完全无法支持跨类复用的需求,只有当该判断逻辑永远不需要被其他类调用时才可以考虑,直接排除。


2. 具体实现方案:通用稳定工具函数的最佳实践

// 单独抽离的公共util模块,比如src/utils/object.ts
export const isEmpty = (data: Record<string, any>): boolean => Object.keys(data).length === 0

// 业务类中直接导入使用
import { isEmpty } from '@/utils/object'
export class UserRepository {
  constructor (private readonly database: DatabaseProtocol) {}

  async findUserByEmail (data: Record<string, any>): Promise<IUser | null> {
    const userCollection = this.database.collection('users')

    if (isEmpty(data)) return null

    const user = await userCollection.findOne({ email: data.email })

    return user
  }
}

适用场景

如果isEmpty是逻辑稳定、无副作用、不需要多态实现的通用工具函数,这个方案是最优解:

  • 代码简洁,不需要额外修改类的构造函数注入依赖
  • 复用成本极低,任意需要的类直接导入即可使用
  • 符合绝大多数项目中通用工具函数的编码规范

3. 接口注入方案:需要多态/测试mock场景的最佳实践

// 接口定义
export interface IsEmptyProtocol {
  isEmpty: (data: Record<string, any>) => boolean
}

// 业务类通过构造函数注入实现
export class UserRepository {
  constructor (
    private readonly database: DatabaseProtocol,
    private readonly emptyValidator: IsEmptyProtocol
  ) {}

  async findUserByEmail (data: Record<string, any>): Promise<IUser | null> {
    const userCollection = this.database.collection('users')

    if (this.emptyValidator.isEmpty(data)) return null

    const user = await userCollection.findOne({ email: data.email })

    return user
  }
}

适用场景

如果满足以下任意一个条件,这个方案是更合理的选择:

  • isEmpty的判断逻辑存在多种实现变体,比如不同业务场景下对“空”的定义不同,需要灵活替换实现
  • 需要对UserRepository做单元测试,希望可以mock掉isEmpty的实现,避免测试依赖外部工具函数的逻辑
  • 项目严格遵循依赖倒置原则,要求所有外部依赖都通过注入的方式引入

最终选型建议

绝大多数常规业务场景下,直接选择具体实现方案即可,既满足复用需求也没有过度设计的问题。如果有上述的多态、测试mock需求,再考虑切换为接口注入方案。

内容的提问来源于stack exchange,提问作者Christian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 18:57:03