You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:35:17