异步操作的附加抽象层

问题描述 投票:0回答:1

我的问题将是更多的设计或架构相关。只需要更有经验的工程师的建议。

我现在正在学习RxJava / RxAndroid,并希望根据经验教训在应用程序中替换我的异步逻辑。

我有一个基于MVP模式的应用程序,几乎每个Presenter都与Repository通信。为了避免ANR,我在Repository类中使用了一些异步逻辑(实际上并不重要的是使用什么机制:ThreadPoolExecutor,AsyncTask或JobScheduler)。

所以我决定用一组RxJava类替换那个异步逻辑,但我遇到了一个有趣的问题。从架构的角度来看,我应该在哪里实现异步逻辑?

恕我直言,有两种可能的选择(可能还有其他选项):

  1. 重写每个存储库并用新的Reactive逻辑替换所有自定义异步逻辑;
  2. 从Repository中删除所有异步逻辑(使类完全同步)并将其移动到某个外部实体(将其命名为“RepositoryAsyncRunner”)。

如果我遵循Case#1,那么需要为每个存储库更改接口,它将以相同的方式工作。看起来像是不必要的改变,因为逻辑没有改变。唯一改变的是异步执行的方式。

如果我遵循Case#2,那么我的Presenter将与该异步包装器而不是普通存储库进行通信,并且所有异步逻辑将封装在单独的类中。

坦率地说,我喜欢第二种方法。如果我稍后改变主意并希望用另一个很酷的库替换RxJava,我必须只更改AsyncRunner而不修改Repository类,它的接口和相关的单元测试(甚至可能不会更改Presenter的测试)。同样使用这种方法我将有两个不同的类用于两个不同的目的(SOLID中的'S':)

很高兴能得到一些帮助来解决这种情况。

android architecture rx-java mvp software-design
1个回答
0
投票

如果你使用RxJava但你的存储库没有暴露像ObservableSingle等Rx原语,你会错过RxJava的一些好处,比如可链接性,管道中的转换,没有嵌套的回调等。

因此,如果要从使用RxJava获得最佳结果,您的存储库应该具有返回Rx原语的方法。

但是,如果您担心必须转移到另一个异步组合框架,则可以始终使用Java异步任务原语Callable。这些是常见的,可以在各种框架之间轻松转换。

例:

public class CallableFactory {

    private final RetrofitService retrofitService;

    public CallableFactory(RetrofitService retrofitService) {
        this.retrofitService = retrofitService;
    }

    public Callable<String> getCallable(final Integer id) {
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                return retrofitService.getById()
                        .enqueue();
            }
        };
    }
}

那么Rx存储库看起来像这样:

class RealRepository implements RxRepository {

    private final CallableFactory callableFactory;

    @Inject
    RealRepository(CallableFactory callableFactory) {
        this.callableFactory = callableFactory;
    }

    @Override
    public Observable<String> retrieveById(final Integer id) {
        return Observable.fromCallable(callableFactory.getCallable(id));
    }
}

如果你不得不转移到Google Guava并使用ListenableFuture而不是Rx,你可以重新使用Callable:

class RealGuavaRepository implements GuavaRepository {

    private final CallableFactory callableFactory;

    @Inject
    RealRepository(CallableFactory callableFactory) {
        this.callableFactory = callableFactory;
    }

    @Override
    public ListenableFuture<String> retrieveById(final Integer id) {
        return MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())
                .submit(callableFactory.getCallable(id));
    }
}

在最后一个例子中对Executor的严格依赖并不理想,但它是一种简化 - 你可以很容易地注入这些。

编辑:如果你在谈论一个Android项目,那么官方Google Android架构蓝图中就有一个很好的例子here

© www.soinside.com 2019 - 2024. All rights reserved.