
本文介绍一种基于组合(composition)与接口抽象的面向对象设计方案,解决多类间存在“部分属性/行为重叠”却无法单纯依赖继承的问题,兼顾可维护性、可扩展性与多态支持。
本文介绍一种基于组合(composition)与接口抽象的面向对象设计方案,解决多类间存在“部分属性/行为重叠”却无法单纯依赖继承的问题,兼顾可维护性、可扩展性与多态支持。
在面向对象设计中,当多个类共享部分而非全部行为与状态时,盲目采用单继承链往往导致代码冗余、逻辑耦合或违反开闭原则。以共享单车站(BikeStation)、皮划艇站(CanoeStation)和复合站(BikeAndCanoeStation)为例:前两者各自拥有专属属性与方法,而第三类并非简单“叠加”,而是需复用前两类的核心能力——此时,继承不是银弹,组合才是正解。
✅ 推荐方案:组合 + 接口契约 + 抽象基类协同
我们应将共性行为抽象为接口,将专属能力封装为可复用组件,并通过组合方式在复合类中按需装配,同时保留统一的多态入口。具体分三步实现:
1. 定义能力契约接口(明确职责边界)
public interface BikeCapable {
void borrowBike();
void returnBike();
int getAvailableBikes();
}
public interface CanoeCapable {
void borrowCanoe();
void returnCanoe();
int getAvailableCanoes();
}✅ 优势:接口聚焦单一能力,便于独立演进;任何类均可实现一个或多个接口,天然支持多态调用。
2. 实现原子能力组件(高内聚、可复用)
public class BikeStation implements BikeCapable {
private int availableBikes = 5;
@Override
public void borrowBike() { /* ... */ }
@Override
public void returnBike() { /* ... */ }
@Override
public int getAvailableBikes() { return availableBikes; }
}
public class CanoeStation implements CanoeCapable {
private int availableCanoes = 3;
@Override
public void borrowCanoe() { /* ... */ }
@Override
public void returnCanoe() { /* ... */ }
@Override
public int getAvailableCanoes() { return availableCanoes; }
}⚠️ 注意:这些组件不再继承 Station,而是纯粹的能力提供者,可被任意上下文复用(如移动端服务、统计模块等)。
立即学习“Java免费学习笔记(深入)”;
3. 构建复合类并委托行为(组合优于继承)
public abstract class Station {
protected String name;
protected String location;
public Station(String name, String location) {
this.name = name;
this.location = location;
}
// 统一多态入口:各子类按需实现差异化逻辑
public abstract void displayInventory();
}
public class BikeAndCanoeStation extends Station
implements BikeCapable, CanoeCapable {
private final BikeStation bikeStation;
private final CanoeStation canoeStation;
public BikeAndCanoeStation(String name, String location) {
super(name, location);
this.bikeStation = new BikeStation(); // 或从 DI 容器获取
this.canoeStation = new CanoeStation();
}
// 委托 BikeCapable 行为
@Override
public void borrowBike() { bikeStation.borrowBike(); }
@Override
public void returnBike() { bikeStation.returnBike(); }
@Override
public int getAvailableBikes() { return bikeStation.getAvailableBikes(); }
// 委托 CanoeCapable 行为
@Override
public void borrowCanoe() { canoeStation.borrowCanoe(); }
@Override
public void returnCanoe() { canoeStation.returnCanoe(); }
@Override
public int getAvailableCanoes() { return canoeStation.getAvailableCanoes(); }
// 复合业务逻辑示例
@Override
public void displayInventory() {
System.out.printf("%s (%s): %d bikes, %d canoes%n",
name, location,
getAvailableBikes(),
getAvailableCanoes()
);
}
}✅ 额外收益与最佳实践
- 可扩展性:新增 ElectricScooterStation?只需定义 ScooterCapable 接口 + 实现类,再让 BikeAndCanoeAndScooterStation 组合三者即可,零修改现有代码。
- 测试友好:BikeAndCanoeStation 的单元测试可轻松 Mock BikeStation 和 CanoeStation,隔离依赖。
- 避免“菱形继承”陷阱:Java 不支持多继承,但组合+接口完美规避该限制,且语义更清晰。
- DI 友好:实际项目中,bikeStation 和 canoeStation 应通过构造器注入(如 Spring),便于配置化与生命周期管理。
? 总结:当类间关系呈现“部分能力重用”而非“is-a”层级时,优先选择 组合(Composition) + 接口(Interface) + 委托(Delegation) 三件套。它比继承更灵活、比复制粘贴更健壮,是构建可持续演化的 OOP 系统的核心范式。










