将Java长继承树重构为组合/聚合的问题咨询
继承转组合的重构优化方案
问题背景
原Java程序存在深度继承链(如A <- B <- C <- D),共约90个类,最深层级6-8层,导致修改、测试派生类困难,计划重构为组合/聚合模式,需满足以下核心需求:
- 能调用派生类独有的方法,同时可访问基类方法
- 调用基类定义的方法时,能触发派生类的重写逻辑(如
d.doSomething()能执行D、C、B、A的对应逻辑) - 保留多态行为,兼容现有
A a = new D()的写法 - 实现基类与派生类的松耦合
当前已实现的方案通过继承式接口层级+组合注入前序类解决了多态和方法调用问题,但存在大量方法转发代码重复的问题——每个类都要重写接口中所有父级方法,手动转发给组合的实例,在90个类的规模下会导致代码冗余度极高。
优化思路
1. 提取转发逻辑到抽象类,消除重复代码
针对每个接口层级,创建对应的抽象转发类,封装对组合实例的方法转发逻辑,具体业务类只需继承该抽象类,仅实现自身新增或需要重写的方法:
// 抽象转发类:封装InterfaceForA的方法转发 abstract class ForwardingA implements InterfaceForA { protected final InterfaceForA delegate; public ForwardingA(InterfaceForA delegate) { this.delegate = delegate; } @Override public void doSomething() { delegate.doSomething(); } } // 抽象转发类:继承ForwardingA,封装InterfaceForB的方法转发 abstract class ForwardingB extends ForwardingA implements InterfaceForB { protected final InterfaceForB delegate; public ForwardingB(InterfaceForB delegate) { super(delegate); this.delegate = delegate; } @Override public void doMore() { delegate.doMore(); } } // 同理创建ForwardingC、ForwardingD抽象类
简化后的业务类示例:
class A implements InterfaceForA { public void doSomething(){ System.out.println("A did something"); } } class B extends ForwardingB { public B(InterfaceForB delegate) { super(delegate); } // 仅需实现新增/重写的方法 @Override public void doMore(){ delegate.doSomething(); System.out.println("B did more"); } } class D extends ForwardingD { public D(InterfaceForD delegate) { super(delegate); } @Override public void doSomething(){ delegate.doSomething(); System.out.println("D did something"); } public void doTheMost(){ delegate.doEvenMore(); System.out.println("D did the most"); } }
2. 调整Builder,面向接口而非具体实现
原Builder直接依赖具体类,改为依赖接口可进一步解耦,后续替换实现类时无需修改Builder的方法签名:
class Builder { public InterfaceForA createInstanceOfA(){ return new A(); } public InterfaceForB createInstanceOfB(){ return new B(createInstanceOfA()); } public InterfaceForC createInstanceOfC(){ return new C(createInstanceOfB()); } public InterfaceForD createInstanceOfD(){ return new D(createInstanceOfC()); } }
3. 用装饰器模式的钩子方法优化重写逻辑
当前方案本质是装饰器模式的变体,可在抽象转发类中预留钩子方法,让子类更清晰地分离父级逻辑与自身增强逻辑:
abstract class ForwardingA implements InterfaceForA { protected final InterfaceForA delegate; public ForwardingA(InterfaceForA delegate) { this.delegate = delegate; } @Override public void doSomething() { beforeDoSomething(); delegate.doSomething(); afterDoSomething(); } // 钩子方法,子类可按需重写 protected void beforeDoSomething() {} protected void afterDoSomething() {} }
比如D类的doSomething可简化为:
class D extends ForwardingD { public D(InterfaceForD delegate) { super(delegate); } @Override protected void afterDoSomething() { System.out.println("D did something"); } public void doTheMost(){ delegate.doEvenMore(); System.out.println("D did the most"); } }
4. 精简接口层级,避免过度设计
如果中间层级的接口(如InterfaceForB、InterfaceForC)没有独立的使用场景(即很少有代码直接依赖它们而非顶层/底层接口),可以合并部分接口,减少层级复杂度。例如仅保留InterfaceForA和InterfaceForD,中间的方法定义移到抽象转发类中,无需对外暴露。
5. 利用组合优势优化测试
组合模式天生具备更好的可测试性,每个业务类可单独测试:测试D类时无需构建完整的A->B->C链,只需MockInterfaceForC的实例,专注验证D自身的逻辑:
@Test void testDDoSomething() { InterfaceForC mockC = Mockito.mock(InterfaceForC.class); D d = new D(mockC); d.doSomething(); Mockito.verify(mockC).doSomething(); // 验证输出包含"D did something" }
内容的提问来源于stack exchange,提问作者coz
相关产品推荐
相关产品推荐

