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

Java接口模块化困境:API依赖实现类如何破局?

解决API与实现分离时的依赖倒置问题

你当前的核心问题是Builder接口的静态工厂方法直接依赖实现类,导致本应作为依赖顶层的API模块反而依赖了实现模块,打破了“实现依赖API”的分层原则。下面是几种可行的解决方案,包括你问到的依赖注入方案:

方案1:将静态工厂方法迁移到实现模块

把原本放在Builder接口里的create方法移到实现模块的独立工厂类中,让API模块只保留纯接口定义,彻底切断对实现类的依赖。

API模块(Api/Builder.java):

public interface Builder {
    // 仅定义Builder的业务方法,比如:
    Object build();
}

实现模块(Impl/BuilderFactory.java):

public class BuilderFactory {
    private static final int N = 5; // 示例版本阈值

    public static Builder create(int version) {
        if (version < N) {
            return new SubBuilder1();
        } else {
            return new SubBuilder2();
        }
    }

    static class SubBuilder1 implements Builder {
        @Override
        public Object build() {
            // 具体实现逻辑
            return new Object();
        }
    }

    static class SubBuilder2 implements Builder {
        @Override
        public Object build() {
            // 具体实现逻辑
            return new Object();
        }
    }
}

上层代码通过BuilderFactory.create(version)获取Builder实例,此时依赖关系是实现模块 → API模块,完全符合分层要求。

方案2:使用Java SPI机制实现动态加载

如果需要支持后续扩展更多Builder实现,Java自带的SPI(服务提供者接口)是更灵活的选择,它允许实现模块主动注册实现类,API模块通过动态加载获取实例,无需编译期依赖。

步骤1:API模块定义接口并添加版本判断方法

public interface Builder {
    Object build();
    // 新增方法,判断当前实现是否支持指定版本
    boolean supports(int version);
}

步骤2:实现模块注册服务提供者
在实现模块的META-INF/services目录下创建一个以API接口全类名为文件名的文件(比如com.yourpackage.api.Builder),文件内容写入实现类的全类名:

com.yourpackage.impl.SubBuilder1
com.yourpackage.impl.SubBuilder2

步骤3:实现类实现supports方法

public class SubBuilder1 implements Builder {
    @Override
    public Object build() {
        // 实现逻辑
        return new Object();
    }

    @Override
    public boolean supports(int version) {
        return version < 5; // 匹配版本阈值
    }
}

public class SubBuilder2 implements Builder {
    @Override
    public Object build() {
        // 实现逻辑
        return new Object();
    }

    @Override
    public boolean supports(int version) {
        return version >= 5;
    }
}

步骤4:API模块或上层提供加载器

public class BuilderLoader {
    public static Builder create(int version) {
        ServiceLoader<Builder> loader = ServiceLoader.load(Builder.class);
        for (Builder builder : loader) {
            if (builder.supports(version)) {
                return builder;
            }
        }
        throw new IllegalArgumentException("No Builder supports version: " + version);
    }
}

这种方式下,API模块完全不依赖实现类,实现模块只需依赖API接口,同时支持动态扩展新的Builder实现。

方案3:依赖注入(DI)完全解耦

依赖注入非常适合这种场景,通过容器管理实现类的实例化,API模块无需关心具体实现的创建逻辑。以Spring为例:

API模块:保留纯Builder接口不变。

实现模块:将实现类注册为Spring Bean,并添加版本判断逻辑:

@Component
public class SubBuilder1 implements Builder {
    @Override
    public Object build() {
        return new Object();
    }

    public boolean supports(int version) {
        return version < 5;
    }
}

@Component
public class SubBuilder2 implements Builder {
    @Override
    public Object build() {
        return new Object();
    }

    public boolean supports(int version) {
        return version >= 5;
    }
}

实现模块提供获取实例的Bean:

@Component
public class BuilderProvider {
    @Autowired
    private List<Builder> builderList;

    public Builder getBuilder(int version) {
        for (Builder builder : builderList) {
            if (((VersionSupport) builder).supports(version)) {
                return builder;
            }
        }
        throw new IllegalArgumentException("Unsupported version");
    }
}

// 定义通用的版本支持接口让Builder实现
public interface VersionSupport {
    boolean supports(int version);
}

上层代码通过注入BuilderProvider来获取对应版本的Builder实例,依赖关系完全符合“实现依赖API”的原则,同时容器负责实例化和管理实现类,进一步降低耦合。

内容的提问来源于stack exchange,提问作者LGDGODV

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:47:11