Android解耦(一)基于接口的module解耦

一、如何实现基于接口的module解耦

基于接口的module解耦可以通过以下几个步骤来实现:

1. 创建一个公共module(base module),并在其中定义所有需要被其他module调用或通信的接口(interface)。例如:

java 复制代码
// base module
public interface IPayService {
    // 支付验证方法
    boolean verifyPayment(String orderId);
}

public interface ILoginService {
    // 获取用户信息方法
    User getUserInfo();
}

2. 在各个子module中分别实现这些接口,并向公共module注册自己的实现类(implementation)。这里有两种注册方式:一种是使用Java SPI技术,在src/main/resources/META-INF/services目录下创建以接口全限定名为文件名的文本文件,并在其中写入对应实现类全限定名;另一种是使用编译时注解,在实现类上添加@AutoService(Interface.class)注解,并引入Google AutoService库。例如:

java 复制代码
// pay module
@AutoService(IPayService.class)
public class PayServiceImpl implements IPayService {
    @Override
    public boolean verifyPayment(String orderId) {
        // 实现支付验证逻辑
        return true;
    }
}
java 复制代码
// login module
@AutoService(ILoginService.class)
public class LoginServiceImpl implements ILoginService {
    @Override
    public User getUserInfo() {
        // 实现获取用户信息逻辑
        return new User("Tom", 18);
    }
}

3. 在公共module中创建一个组件管理类(ComponentManager),并在其中使用Java SPI技术加载所有已注册的组件接口和组件实现类之间对应关系,并提供一个静态方法来根据组件接口类型获取对应组件实现类对象。例如:

java 复制代码
// base module
public class ComponentManager {

    private static final Map<Class<?>, Object> COMPONENT_MAP = new HashMap<>();

    static {
        // 使用Java SPI技术加载所有已注册的组件接口和组件实现类之间对应关系
        ServiceLoader.load(Object.class).forEach(service -> {
            Class<?>[] interfaces = service.getClass().getInterfaces();
            if (interfaces != null && interfaces.length > 0) {
                for (Class<?> interfaceClass : interfaces) {
                    COMPONENT_MAP.put(interfaceClass, service);
                }
            }
        });
    }

    // 提供一个静态方法来根据组件接口类型获取对应组件实现类对象
    public static <T> T getComponent(Class<T> interfaceClass) {
        return (T) COMPONENT_MAP.get(interfaceClass);
    }
}

在其他module中,通过公共module的组件管理类(ComponentManager)获取到对应接口的实现类对象,并调用其方法进行通信或功能执行。例如:

java 复制代码
// social module
public class SocialActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_social);

        // 通过公共module的组件管理类(ComponentManager)获取到登录模块的接口实现类对象
        ILoginService loginService = ComponentManager.getComponent(ILoginService.class);

        // 调用登录模块的接口方法获取用户信息
        User user = loginService.getUserInfo();

        // 显示用户信息
        TextView tvUserName = findViewById(R.id.tv_user_name);
        TextView tvUserAge = findViewById(R.id.tv_user_age);
        tvUserName.setText(user.getName());
        tvUserAge.setText(String.valueOf(user.getAge()));
    }
}

二、基于接口的module解耦的优缺点

基于接口的module解耦有以下优点:

1. 解耦彻底,各个子module之间不需要有任何依赖或引用,只需要依赖公共module即可。
2. 通信简单高效,支持所有基本类型和类类型,像在调用module内部接口一样方便。
3. 实现灵活多样,可以根据不同场景或需求选择不同的接口实现类,并动态替换或切换。

基于接口的module解耦也有以下缺点:

1. 需要额外创建一个公共module,并在其中定义所有需要被其他module调用或通信的接口,增加了代码量和维护成本。
2. 需要使用Java SPI技术或编译时注解来注册组件接口和组件实现类之间对应关系,增加了编译时间和运行时开销。
3. 需要注意避免循环依赖或重复注册等问题,否则可能导致程序崩溃或异常。

三、基于接口的module解耦的使用场景

基于接口的module解耦适合以下使用场景:

1. 当项目功能较多且复杂时,需要将一个app主模块拆分成多个子模块(module),每个子模块负责一个独立的功能或业务场景。
2. 当子模块之间需要相互调用或通信时,需要一种方式来实现子模块之间的解耦和通信。

当子模块之间调用或通信涉及到多种数据类型时,需要一种方式来支持所有基本类型和类类型。
3. 当子模块之间调用或通信可能发生变化时,需要一种方式来实现灵活多样的切换或替换。

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀

相关推荐
Mr YiRan11 分钟前
网络请求API监控与网络切换埋点
android·网络
美狐美颜sdk4 小时前
直播APP开发技术栈详解:视频美颜SDK、人脸识别与实时渲染
android·人工智能·音视频·美颜sdk·直播美颜sdk
奈斯先生Vector9 小时前
当模型版本不断变化,RelayRouter 能否帮助 AI 应用摆脱深度绑定
android·java·人工智能·开源·aigc
TimeFine9 小时前
让强模型做“总工”,让高性价比模型写代码
android
又见情义11 小时前
RK3568 Android 13 屏蔽 healthd 电池日志经验分享
android
古法安卓14 小时前
Android-Fork 机制详解
android·java·android studio
Android打工仔14 小时前
不要在 Data 层随意把 Cold Flow 转换成 Hot Flow
android·架构·kotlin
峥嵘life15 小时前
2026免费的 opencode 使用分享:Windows端 + 服务器CLI 实战总结
android·大数据·开发语言
杉氧15 小时前
拒绝重复造轮子:我写了一个生产级的 Kotlin 协程与 Flow 工具库(CoroutineKit)
android·kotlin·workflow
恋猫de小郭16 小时前
Flutter GSoC 2026 提案进度解读,补上 DevTools、FFI 和原生平台的关键缺口
android·前端·flutter