上篇博客讨论了RxJava流程控制中的一些问题,我本人并没有想到什么好的解决方案。
最近学习了设计模式,发现状态模式可以更优雅的解决这类问题。

首先我们定义一个正常搜索状态

public class NormalState implements SearchMVP.Presenter {
    SearchMVP.Model mModel;
    SearchMVP.View mView;
    SearchPresenter mSearchPresenter;

    public NormalState(SearchMVP.Model model, SearchMVP.View view, SearchPresenter searchPresenter) {
        mModel = model;
        mView = view;
        mSearchPresenter = searchPresenter;
    }

    @Override
    public void search(final String key) {
        mModel.search(key).subscribe(new Subscriber<List<Product>>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                mView.showSearchFailed();
            }

            @Override
            public void onNext(List<Product> productList) {

                if (productList.isEmpty()) { //切换到推荐状态 然后请求
                    mSearchPresenter.setRecommendState();
                    mSearchPresenter.search(key);
                } else {
                    mView.showSearchResults(productList);
                }
            }
        });
    }
}

NormalState 实现了SearchMVP.Presenter接口,并且拥有SearchPresenter的引用
然后是修改之后的 SearchPresenter

public class SearchPresenter implements SearchMVP.Presenter {

    NormalState mNormalState;
    RecommendState mRecommendState;
    SearchMVP.Presenter mState;

    public SearchPresenter(SearchMVP.Model model, SearchMVP.View view) {
        mNormalState = new NormalState(model, view, this);
        mRecommendState = new RecommendState(model, view);
        mState = mNormalState;
    }

    public void setNormalState() {
        this.mState = mNormalState;
    }

    public void setRecommendState() {
        this.mState = mRecommendState;
    }

    @Override
    public void search(String key) {
        mState.search(key);
    }


}

SearchPresenter已经变成了一个代理类,把实际的请求转交给内部的各种状态类。
最后是RecommendState:

public class RecommendState implements SearchMVP.Presenter {

    SearchMVP.Model mModel;
    SearchMVP.View mView;

    public RecommendState(SearchMVP.Model model, SearchMVP.View view) {
        mModel = model;
        mView = view;
    }

    @Override
    public void search(String key) {
        mModel.recommend()
                .subscribe(new Subscriber<List<Product>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        mView.showSearchFailed();
                    }

                    @Override
                    public void onNext(List<Product> productList) {
                        mView.showRecommendResults(productList);
                    }
                });
    }
}

此时我陷入了迷茫,这算不算为了设计模式而设计模式呢,让我们再看看一开始的代码,对比一下:

public class SearchPresenter implements SearchMVP.Presenter {
    SearchMVP.Model mModel;
    SearchMVP.View mView;

    public SearchPresenter(SearchMVP.Model model, SearchMVP.View view) {
        mModel = model;
        mView = view;
    }

    @Override
    public void search(String key) {
        mModel.search(key)
                .subscribe(new Subscriber<List<Product>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        mView.showSearchFailed();
                    }

                    @Override
                    public void onNext(List<Product> products) {
                        //
                        if (products.isEmpty()) {
                            loadRecommend();
                        } else {
                            mView.showSearchResults(products);
                        }

                    }
                });
    }

    private void loadRecommend() {
        mModel.recommend()
                .subscribe(new Subscriber<List<Product>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        mView.showSearchFailed();
                    }

                    @Override
                    public void onNext(List<Product> productList) {
                        mView.showRecommendResults(productList);
                    }
                });
    }

}

貌似,一开始的代码更简洁更容易理解此处输入图片的描述。也可能和我这个例子太简单有关系,如果各种状态切换逻辑比较复杂,使用设计模式更加容易控制,而且方便单元测试。