一、如何完成依据接口的module解耦

依据接口的module解耦能够经过以下几个过程来完成:

1. 创立一个公共module(base module),并在其中界说一切需求被其他module调用或通讯的接口(interface)。例如:

// 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库。例如:

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

3. 在公共module中创立一个组件管理类(ComponentManager),并在其中运用Java SPI技能加载一切已注册的组件接口和组件完成类之间对应联系,并提供一个静态办法来依据组件接口类型获取对应组件完成类目标。例如:

// 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)获取到对应接口的完成类目标,并调用其办法进行通讯或功用执行。例如:

// 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老皮!!!欢迎大家来找我探讨交流