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

跨项目场景下如何重构MyClassA实现Data的懒加载实例化?

可行实现方案与适用设计模式

一、核心思路

由于项目A不能直接依赖项目B,必须通过解耦方式让项目A获取到项目B中SpecialData的实例,同时满足移除setter、懒加载的需求。以下是几种落地可行的方案:


二、具体实现方式

1. 服务提供者模式(SPI)

这是Java原生的跨模块解耦方案,适配单向依赖下的接口实现加载场景:

  • 步骤1:确保项目A中的Data是公共接口,在项目B的src/main/resources/META-INF/services/目录下创建文件,文件名是Data接口的全限定名(如com.testa.Data),文件内容写入SpecialData的全限定名(com.testb.SpecialData)
  • 步骤2:修改项目A的MyClassA:
package com.testa;

import java.util.ServiceLoader;

public class MyClassA {
    private Data data;

    public Data getData() {
        if (data != null) {
            return data;
        }
        if (projectB.isEnabled) {
            ServiceLoader<Data> loader = ServiceLoader.load(Data.class);
            for (Data dataImpl : loader) {
                // 通过类名匹配目标实现,避免项目A直接依赖SpecialData
                if ("com.testb.SpecialData".equals(dataImpl.getClass().getName())) {
                    this.data = dataImpl;
                    return data;
                }
            }
        }
        throw new IllegalStateException("Data instance not available");
    }
}

2. 工厂方法模式+依赖注入

通过工厂接口封装实例创建逻辑,实现彻底解耦:

  • 步骤1:在项目A中定义DataFactory接口:
package com.testa;

public interface DataFactory {
    Data createData();
    boolean isSupported(); // 对应projectB.isEnabled的判断逻辑
}
  • 步骤2:修改MyClassA,通过SPI或DI框架加载工厂实现:
package com.testa;

import java.util.List;
import java.util.ServiceLoader;

public class MyClassA {
    private Data data;
    private static final List<DataFactory> DATA_FACTORIES = loadFactories();

    private static List<DataFactory> loadFactories() {
        return ServiceLoader.load(DataFactory.class).stream()
                .map(ServiceLoader.Provider::get)
                .toList();
    }

    public Data getData() {
        if (data != null) {
            return data;
        }
        for (DataFactory factory : DATA_FACTORIES) {
            if (factory.isSupported()) {
                this.data = factory.createData();
                return data;
            }
        }
        throw new IllegalStateException("Data instance not available");
    }
}
  • 步骤3:在项目B中实现DataFactory:
package com.testb;

import com.testa.Data;
import com.testa.DataFactory;

public class SpecialDataFactory implements DataFactory {
    @Override
    public Data createData() {
        return new SpecialData();
    }

    @Override
    public boolean isSupported() {
        return projectB.isEnabled;
    }
}

3. 反射实现(应急可用,不推荐)

通过反射动态加载SpecialData,但硬编码类名会降低可维护性,建议配合配置文件存储类名:

package com.testa;

public class MyClassA {
    private Data data;
    // 可将类名抽离到配置文件中
    private static final String SPECIAL_DATA_CLASS = "com.testb.SpecialData";

    public Data getData() {
        if (data != null) {
            return data;
        }
        if (projectB.isEnabled) {
            try {
                Class<?> dataClass = Class.forName(SPECIAL_DATA_CLASS);
                this.data = (Data) dataClass.getDeclaredConstructor().newInstance();
                return data;
            } catch (Exception e) {
                throw new RuntimeException("Failed to create SpecialData instance", e);
            }
        }
        throw new IllegalStateException("Data instance not available");
    }
}

三、适用的设计模式

  • 服务提供者模式(SPI):Java原生的跨模块接口实现加载方案,完美适配单向依赖场景
  • 工厂方法模式:通过工厂接口封装实例创建逻辑,彻底解耦MyClassA与SpecialData的依赖
  • 懒加载(Lazy Initialization):作为实现细节,确保Data实例在第一次使用时才初始化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 04:36:17