清洁架构,用例和实体 [英] Clean Architecture, UseCases and Entities

查看:66
本文介绍了清洁架构,用例和实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,所以我刚开始一个新的Android项目,并想尝试实现Bob叔叔的Clean Architecture.我从RxJava和GitHub示例&中的内容开始有了一个不错的开始样板和Fernando Cerjas的博客(例如这篇文章),但对于如何实现一些UseCases仍然存在一些疑问.

Okay, so I just started a new Android project and wanted to try implementing the Clean Architecture by Uncle Bob. I have a nice beginning using RxJava and stuff from GitHub samples & boilerplates and Fernando Cerjas' blog (like this article), but still have some questions on how to implement some UseCases.

一个实体是否应具有另一个实体的字段(在我的示例中,User具有一个List<Messages>字段)?

Should an Entity have fields that are another Entity (in my example, User having a List<Messages> field)?

或者Presenter是否应该结合UseCases来构建映射到多个实体的ViewModel(然后如何编码映射器?)?

Or should the Presenter combine UseCases to build a ViewModel mapped on multiple Entities (then how to you code the mapper?)?

或者Presenter应该具有与每个UseCase/Entity关联的ViewModel,并创建某种等待所有数据到onNext"以为每个ViewModel调用view.show()吗?

Or should the Presenter have a ViewModel associated to each UseCase/Entity, and create some kind of "wait for all data to onNext" to call the view.show() for each ViewModel?

基本上,UseCases应该只返回实体吗?实体可以由其他实体组成吗(例如在类的字段中)?实体只是愚蠢的数据模型POJO吗?您如何表示联接SQL"查询?

Basically, should UseCases only return Entities? Can an Entity be composed of other entities (as in a field of the class)? Are Entities only dumb datamodels POJOs? How to you represent 'join SQL' queries?

作为示例,让我们以一个简单的用户/消息应用程序为例. 我想实现两个视图:UserListUserDetails:

As an example, let's take a simple users/messages app. I want to implement two views: UserList and UserDetails:

  • UserList显示Users
  • 的列表
  • UserDetails显示用户信息及其最新消息.
  • UserList displays a list of Users
  • UserDetails displays a user's information and its latest messages.

UserList非常简单,我可以看到如何编码相关的UseCase和图层(下面的代码).

UserList is pretty straightforward, and I can see how to code the associated UseCase and layers (code below).

我的问题出在UserDetails屏幕上.

如果我希望同时在视图中传递所有数据(例如,构建由User类组成的ViewModel和字段List),应该如何编码GetUserInfoUseCase? GetUserInfoUseCase的返回值应该是多少? 我应该编写Observable<User> GetUserInfoUseCaseObservable<List<Message>> GetUserLatestMessages并将它们以某种方式合并到演示者中吗?如果是,那么如何处理此问题,因为我的演示者中没有Observables(我只传递了一个Observer作为UseCases参数)?

How should I code my GetUserInfoUseCase if I want all the data to be passed at the view at the same time (like building a ViewModel composed of a User class, with a field List)? What should be the return value of the GetUserInfoUseCase? Should I code a Observable<User> GetUserInfoUseCase and a Observable<List<Message>> GetUserLatestMessages and merge them somehow in my presenter? If yes, how can I manage this, as I don't have the Observables in my Presenter (I'm passing only an Observer as my UseCases parameters)?

public abstract class User {
    public abstract long id();
    public abstract String name();
 ...
}

消息实体

public abstract class Message {
    public abstract long id();
    public abstract long senderId();
    public abstract String text();
    public abstract long timstamp();
 ...
}

GetUsersUseCase

public class GetUsersUseCase extends UseCaseObservableWithParameter<Boolean, List<User>, UsersRepository> {

@Inject
public GetUsersUseCase(UsersRepository UsersRepository,
                              @Named("Thread") Scheduler threadScheduler,
                              @Named("PostExecution") Scheduler postExecutionScheduler) {
    super(usersRepository, threadScheduler, postExecutionScheduler);
}

@Override
protected Observable<List<User>> buildObservable(Boolean forceRefresh) {

    if(forceRefresh)
        repository.invalidateCache();

    return repository.getUsers();
}
}

UsersPresenter

public class UsersPresenter extends BasePresenter<UsersContract.View> implements UsersContract.Presenter {

    @Inject
    GetUsersUseCase mGetUsersUseCase;

    @Inject
    UserViewModelMapper mUserMapper;

    @Inject
    public UsersPresenter() {
    }

    @Override
    public void attachView(UsersContract.View mvpView) {
        super.attachView(mvpView);
    }

    @Override
    public void detachView() {
        super.detachView();

        mGetUsersUseCase.unsubscribe();
    }

    @Override
    public void fetchUsers(boolean forceRefresh) {
        getMvpView().showProgress();

        mGetUsersUseCase.execute(forceRefresh, new DisposableObserver<List<User>>() {
            @Override
            public void onNext(List<User> users) {
                getMvpView().hideProgress();
                getMvpView().showUsers(mUsersMapper.mapUsersToViewModels(users));
            }

            @Override
            public void onComplete() {

            }

            @Override
            public void onError(Throwable e) {
                getMvpView().hideProgress();
                getMvpView().showErrorMessage(e.getMessage());
            }
        });
    }
}

UseCaseObservableWithParameter

public abstract class UseCaseObservableWithParameter<REQUEST_DATA, RESPONSE_DATA, REPOSITORY> extends UseCase<Observable, REQUEST_DATA, RESPONSE_DATA, REPOSITORY> {

    public UseCaseObservableWithParameter(REPOSITORY repository, Scheduler threadScheduler, Scheduler postExecutionScheduler) {
        super(repository, threadScheduler, postExecutionScheduler);
    }

    protected abstract Observable<RESPONSE_DATA> buildObservable(REQUEST_DATA requestData);

    public void execute(REQUEST_DATA requestData, DisposableObserver<RESPONSE_DATA> useCaseSubscriber) {
        this.disposable.add(
                this.buildObservable(requestData)
                        .subscribeOn(threadScheduler)
                        .observeOn(postExecutionScheduler)
                        .subscribeWith(useCaseSubscriber)
        );
    }
}

UseCase

public abstract class UseCase<OBSERVABLE, REQUEST_DATA, RESPONSE_DATA, REPOSITORY> {

    protected final REPOSITORY repository;

    protected final Scheduler threadScheduler;

    protected final Scheduler postExecutionScheduler;

    protected CompositeDisposable disposable = new CompositeDisposable();

    public UseCase(REPOSITORY repository,
                   @Named("Thread") Scheduler threadScheduler,
                   @Named("PostExecution") Scheduler postExecutionScheduler) {
        Timber.d("UseCase CTOR");
        this.repository = repository;
        this.threadScheduler = threadScheduler;
        this.postExecutionScheduler = postExecutionScheduler;
    }

    protected abstract OBSERVABLE buildObservable(REQUEST_DATA requestData);

    public boolean isUnsubscribed() {
        return disposable.size() == 0;
    }

    public void unsubscribe() {
        if (!isUnsubscribed()) {
            disposable.clear();
        }
    }
}

推荐答案

单个问题中有很多问题.让我尝试巩固我认为是您的关键问题

Quite a lot questions within a single question. let me try to consolidate what I think I understood are ur key questions

  • 实体可以互相引用吗?答案将是:是的.同样在 干净的体系结构,您可以创建实体互连的域模型

  • Can Entities reference each other? the answer would be: YES. Also in Clean Architecture u can create a domain model where entities are interconnected

用例应返回什么? 答案:用例定义了最适合用例的输入DTO(数据传输对象)和输出DTO.鲍伯叔叔在书中写道,不应将实体传递给用例或从用例中返回

What should be returned from a UseCase? Answer: UseCases define input DTOs (Data transfer objects) and output DTOs which are most convenient for the use case. in his book uncle bob writes that entities should not be passed to use cases or returned from use cases

演示者的角色是什么?答:理想情况下,演示者仅在转换数据.它将一层最方便的数据转换为另一层最方便的数据.

What is the role of the presenter then? Answer: ideally a presenter is converting data only. It converts data which is most convenient for one layer into data which is most convenient for the other layer.

希望本指南可以帮助您回答您的详细问题

hope this guidance helps u to answer ur detailed questions

您可以在我最近的文章中找到更多详细信息和示例: https://plainionist.github.io/Implementing-Clean-Architecture-UseCases/ https://plainionist.github.io/Implementing-Clean-Architecture-Controller-主持人/

More details and examples you can find in my recent posts: https://plainionist.github.io/Implementing-Clean-Architecture-UseCases/ and https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/

这篇关于清洁架构,用例和实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆