抽象类强制单继承,组合通过“has-a”关系绕过限制,支持多能力来源、运行时替换组件、避免编译连锁失败;推荐接口引用+构造注入;装饰者模式可链式增强行为;语义为“is-a”用继承,“has-a”或跨类型复用能力则用组合。

Java 中抽象类强制单继承,但通过组合(Composition)能自然绕过这个限制,让类拥有多个“能力来源”,既保持结构清晰,又避免多重继承的歧义问题。
用组合替代多继承:把“是什么”变成“有什么”
抽象类表达的是“is-a”关系(比如 Dog is an Animal),而组合表达的是“has-a”关系(比如 Dog has a Tail, has a BarkStrategy, has a DietPlan)。这种转变让设计更灵活:
- 一个类可以持有任意多个其他类的实例,不受 extends 数量限制
- 运行时可替换组件(如切换不同的 BarkStrategy),而继承关系在编译期就固定了
- 避免父类变更引发的连锁编译失败——组合对象内部实现变化,不影响使用者
典型组合写法:字段 + 接口引用 + 构造注入
推荐用接口类型声明组合字段,再通过构造方法传入具体实现。这样既解耦,又便于测试和扩展:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 定义能力接口:Flyable、Swimmable、Trainable
- 创建具体实现类:WingedFlight、DuckSwim、ClickerTraining
- 在主类中组合:
private final Flyable flight; <br> private final Swimmable swim; <br> private final Trainable training;
构造时传入,后续调用flight.fly()、swim.swim()即可
搭配装饰者模式,动态叠加行为
当需要按需增强功能(比如给一只鸭子临时加“闪光羽”或“静音模式”),装饰者是组合的进阶用法:
- 所有装饰者都实现同一接口(如 Duck)
- 每个装饰者内部持有一个 Duck 实例,并在其前后添加逻辑
- 可链式组合:
new SilentDuck(new ShinyDuck(new RealDuck())) - 完全避开继承层级,也不需要修改原始类
什么时候该坚持继承,什么时候果断用组合?
判断核心看语义是否真实存在“血缘”:
- 如果子类确实是父类的一种(Penguin is a Bird),且共享大量状态和基础逻辑,用抽象类继承合理
- 如果只是“具备某项能力”(Penguin can slide),或能力可能被不同种类对象复用(Seal also slides),那就抽成接口 + 组合
- 当发现子类要同时继承两个抽象类才能工作,说明设计已越界——此时应拆出接口,把共性行为下沉为组合组件
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










