接口是依赖注入的契约主体,业务代码应面向接口编程并声明接口类型字段;抽象类封装共性技术逻辑但不参与注入链,仅作子类实现辅助。

接口和抽象类在依赖注入中扮演不同角色:接口定义“能做什么”,是解耦的契约基础;抽象类提供“部分怎么做”,是可复用的技术支撑。二者配合使用,关键在于分层清晰、职责分明。
接口作为依赖注入的契约主体
业务代码应只面向接口编程,字段和构造参数都声明为接口类型。这样Spring等容器才能通过@Autowired或Guice的@Inject自动注入具体实现,替换实现时无需修改调用方。
- 例如定义
PaymentService接口,多个实现类(AlipayService、WechatPayService)都实现它 - 订单服务中写
private final PaymentService paymentService;,通过构造器注入 - 运行时容器按类型匹配Bean,业务类完全不知道也不关心具体是哪个支付渠道
抽象类用于封装共性逻辑,但不参与依赖注入链
抽象类适合沉淀稳定、非业务性的技术逻辑,比如重试机制、日志模板、统一异常包装。它本身不应被其他模块直接依赖,也不该实现业务接口。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 例如
AbstractHttpClient封装连接池、超时、Header设置,子类继承后只需专注URL拼接和响应解析 - 它的public方法建议设为
final,仅开放protected钩子供定制 - 业务层仍依赖
UserService这样的接口,而非抽象类;抽象类只是子类内部的实现辅助
依赖注入框架如何协同两者
主流框架(Spring、Guice)天然支持接口注入,对抽象类的支持则需明确配置——抽象类通常不注册为Bean,而是由其实现类作为Bean被注入。
立即学习“Java免费学习笔记(深入)”;
- Spring中,用
@Service或@Component标注具体实现类,接口类型字段自动装配 - 若抽象类含通用初始化逻辑,可通过
@PostConstruct在其子类中触发 - Guice中用
bind(PaymentService.class).to(AlipayService.class)绑定接口与实现,抽象类不参与绑定
避免常见误用
混淆接口与抽象类的定位,容易导致耦合回潮或设计僵化。
- 不要让抽象类实现业务接口——这会让高层模块间接依赖具体实现骨架
- 不要在业务类中
new抽象类子类——必须交由容器管理生命周期 - 接口保持小而专(如
OrderValidator、OrderNotifier),比大而全的OrderService更易组合和测试

















