java不支持多继承,但可通过组合实现复用:主类以接口类型持有功能对象(has-a),通过依赖注入解耦,明确职责并提升可维护性与可测试性。

Java 不允许一个类用 extends 同时继承多个父类,但可以通过组合(Composition)把多个类的功能“装进来”,让当前类拥有它们的能力——这不是继承关系(is-a),而是持有关系(has-a),更灵活、更安全。
用成员变量聚合功能类
把需要复用的类作为字段声明在主类中,通过调用其方法来实现功能。关键在于定义清晰的接口,再让具体类去实现它,主类只依赖接口,不绑定具体实现。
- 先定义行为契约:比如
Logger接口声明log(String msg),Notifier接口声明notify(String content) - 编写具体实现类:如
FileLogger、SlackNotifier,各自实现对应接口 - 在主业务类中声明接口类型字段:
private Logger logger;、private Notifier notifier; - 通过构造函数或 setter 注入实例,避免硬编码 new,便于替换和测试
手动转发方法调用
主类自身不直接实现逻辑,而是把请求转给内部持有的对象。这种方式明确职责,也避免了接口方法名冲突问题。
- 例如
UserManager类要支持日志和通知,就写两个方法:public void recordAction(String action) { logger.log(action); } public void alertAdmin(String issue) { notifier.notify("ALERT: " + issue); }- 所有业务逻辑集中在主类,底层实现可随时更换(比如从邮件通知换成短信通知),只要接口不变
配合依赖注入提升可维护性
组合本身不强制依赖注入,但搭配 DI 容器(如 Spring)能显著降低耦合度。
- 不用在主类里
new FileLogger(),改由容器自动装配@Autowired private Logger logger; - 不同环境可配置不同实现:开发用
ConsoleLogger,生产用KafkaLogger - 单元测试时轻松 mock 这些依赖,无需启动真实服务
注意避免“伪组合”陷阱
组合不是简单地把一堆类 new 出来塞进字段,核心是解耦与可替换。
- 别让主类直接依赖具体类(如
private FileLogger logger;),否则失去替换能力 - 不要在组合对象里暴露过多细节(比如返回
logger.getFileWriter()),破坏封装 - 如果某个被组合类的状态需要和主类强同步,要考虑是否更适合用继承或回调机制
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











