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

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

问题描述

好的,所以我刚刚开始了一个新的 Android 项目,并想尝试实现 Uncle Bob 的 Clean Architecture.我使用 RxJava 和来自 GitHub 示例的东西有一个很好的开始样板文件和 Fernando Cerjas 的博客(例如 这篇文章),但仍然对如何实现一些用例有一些疑问.

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 字段)?

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应该有一个与每个用例/实体相关联的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?

基本上,用例应该只返回实体吗?一个实体是否可以由其他实体组成(如在类的一个字段中)?实体只是愚蠢的数据模型 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 非常简单,我可以看到如何编写关联的用例和层(下面的代码).

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 代码吗?GetUserInfoUseCase 和一个 Observable>GetUserLatestMessages 并在我的演示者中以某种方式合并它们?如果是,我该如何管理这个,因为我的 Presenter 中没有 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();
 ...
}

获取用户用例

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();
}
}

用户演示者

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)
        );
    }
}

用例

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天全站免登陆