MST

星途 面试题库

面试题:Java接口与抽象类在框架设计中的权衡

在大型Java框架设计中,常常需要在接口和抽象类之间做出选择。请详细分析在哪些情况下更适合使用接口,哪些情况下更适合使用抽象类,并结合如Spring框架等实际的开源框架中的相关代码示例,说明这样选择的原因和带来的影响。
22.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

适合使用接口的情况

  1. 实现多继承:Java 不支持类的多继承,但一个类可以实现多个接口。当一个类需要从多个来源获取行为定义时,接口是很好的选择。例如,在 Spring 的 ApplicationContextAwareBeanNameAware 等接口,一个 Spring 管理的 Bean 可以同时实现多个这样的接口,从而获得不同的功能,如获取应用上下文或获取自身 Bean 名称。
  2. 定义行为契约:当需要定义一组方法的签名,而不关心具体实现,且不同实现之间没有共同状态和通用实现逻辑时,使用接口。比如 Spring 的 InitializingBean 接口,它定义了 afterPropertiesSet 方法,用于在 Bean 属性设置完成后执行一些初始化操作。不同的 Bean 对该方法的实现差异很大,没有通用实现逻辑,只需要遵循这个契约。
  3. 降低耦合度:接口可以实现模块之间的松耦合。例如在 Spring 的依赖注入中,服务层接口与实现类分离。业务代码依赖接口而不是具体实现类,这样在更换实现类时,业务代码无需修改。比如一个 UserService 接口,有 UserServiceImplUserServiceMock 等不同实现,通过接口注入,业务层代码不会因为实现类的变化而受到影响。

适合使用抽象类的情况

  1. 有共同状态和通用实现:当多个子类有共同的成员变量和通用的方法实现时,抽象类更为合适。例如在 Spring 的 AbstractApplicationContext 抽象类,它实现了 ApplicationContext 接口的部分通用方法,如资源加载等,为其子类 ClassPathXmlApplicationContext 等提供了基础实现,子类可以在此基础上进行扩展,减少代码重复。
  2. 模板方法模式:抽象类常被用于实现模板方法模式。比如 Spring 的 JdbcTemplate 类,它是一个抽象类,定义了一系列操作数据库的模板方法,如 queryupdate 等,其中部分方法有通用实现,而一些关键步骤如 mapRow 等由具体子类实现,这种方式将通用流程和具体实现分离,提高代码复用性和灵活性。
  3. 演进式设计:如果接口可能会不断增加新方法,使用抽象类可以避免实现类因为接口方法的增加而被迫修改。在框架的演进过程中,抽象类可以在不破坏已有实现类的情况下添加新的默认实现方法。例如在 Spring 框架的发展过程中,AbstractBeanDefinition 抽象类随着功能的扩展可以添加新的方法并提供默认实现,而不会影响到大量的子类。