清洁架构:结合交互者

时间:2017-05-05 11:20:43

标签: java android clean-architecture

我最近偶然发现了Bob叔叔的Clean Architecture,我很想知道Interactors是否可以执行其他Interactors。

例如,截至目前,这些是我的Interactors:getEmptyAlbums,getOtherAlbums。两者都有Callbacks,它们分别返回Albums列表(Album模型的ArrayList)。

我是否可以让一个名为getAllAlbums的Interactor在其运行块中执行前两个Interactors?

@Override
public void run() {
    getEmptyAlbums.execute();       
}

void onEmptyAlbumsReceived(ArrayList<Album albums){
     getOtherAlbums.execute;
}
void onOtherAlbumsReceived(ArrayList<Album albums){
         mMainThread.post(new Runnable() {
         callback.onAlbumsReceived(albums);
     }
});

4 个答案:

答案 0 :(得分:8)

我的回答是“否”。让我解释一下原因:

  1. 那将打破界限

清洁架构最重要的概念之一就是边界。每个用例都定义一个边界,即系统的垂直层。因此,没有理由让用例知道另一个用例的存在。这些垂直层允许获得用例的独立开发能力和部署能力。假设我们正在团队合作,您开发了GetEmptyAlbums用例,而我正在研究GetAllAlbums用例。如果我自己打个用例,我们不是在独立开发。我们都没有实现独立的可部署性。垂直边界被打破。有关详细信息,请参见《清洁建筑》一书的第152页和第16章。

  1. SRP也将被破坏

假设由于任何原因GetEmptyAlbums业务规则发生更改。您将需要重构该用例。现在也许您需要接受一些输入。如果GetAllAlbums调用GetEmptyAlbums,则也必须重构此用例。换句话说,通过耦合用例,您将添加更多责任。因此,SRP会中断。

  1. DRY仍在投诉

有两种重复: true 重复和偶然重复。通过定义两个或两个以上彼此非常相似的用例,您会意外复制。这是偶然的,因为将来可能会有所不同,并且(这很重要)由于不同的原因。有关此概念,请参见第154页。

  1. 测试变得更加脆弱

与SRP非常相关。如果您对用例A进行了某些更改,而C调用了A,则不仅A测试将中断,C测试也将中断。

总而言之,答案是否定的,您不能从另一个调用用例交互器。但是,如果您想实现一种纯净的“干净架构”方法,则适用此规则,但并非总是正确的决定。

要指出的另一件事是,用例必须声明输入和输出数据结构。我不确定您的相册类是否为实体,但是如果是这样,则那里存在问题。正如鲍勃叔叔所说:“我们不想欺骗并传递边界之间的实体对象”(第207页)。

答案 1 :(得分:6)

我一直在思考同样的事情,在对这个问题发现很少之后,我得出的结论是“是”它可能是 的最佳选择。

我的推理如下:

  1. 单一责任:如果您无法汇总用例,那么每个人都不能真正单一责任。如果没有聚合,则意味着域逻辑最终会出现在表示层中,从而无法实现目的。
  2. DRY:用例可以共享, 应该是合理的。
  3. 为了保留单一责任,我会考虑限制聚合用例仅执行,即执行这些用例并进行任何最终转换。

    鉴于这个问题的年龄,我有兴趣知道你采用了哪种方式以及遇到的问题。

答案 2 :(得分:3)

看看令人惊叹的“清洁架构”一书的第 16 章。鲍勃叔叔在名为“复制”的部分回答了这个问题。有两种类型的重复:

真正的重复 — 引入更改会影响重复代码存在的多个位置。

意外重复——代码现在很相似,但背后的想法不同,随着时间的推移,代码变得不同。

如果是真正的重复,您可以结合使用案例,但要小心,因为随着软件的发展,在意外重复的情况下将它们分开会困难得多。

答案 3 :(得分:0)

我对鲍伯叔叔的工作很陌生,我也正在经历这些完全相同的问题。

我对维护SRP而不重复用例的回答是将用例与交互器分开。这可能是矫kill过正,但对我来说确实很好。

我将用例放在与交互器分开的自己的文件中,以便所有单独的交互器都可以使用他们想要和共享的任何用例。一直以来,交互器只是在“使用”(导入,依赖等)它想要的任何用例。

通过这种方式使我的交互器变得非常简单,并且实际上只是一个容器,用于进行所需的依赖项注入以及某些类级别的成员var。

因此,总而言之,getAllAlbums,getEmptyAlbums和getOtherAlbums用例成为它们自己的文件并遵循SRP,并且您有一个Interactor类,该类可以按需和/或按顺序将用例拼接在一起。

最近我也一直在使用例仅用于实际的业务逻辑,而不包括来自依赖项注入网关(如数据库或网络调用)的内容。然后,我将这些依赖网关操作的代码放入操作用例的方法中。

现在,如果您在用例中仅具有“黑盒”业务逻辑概念,则可以在不包含紧密耦合的依赖关系的情况下进行测试。因此,例如,如果您要制作“ Tic Tac Toe”游戏,那么您的用例(快速浏览)将只讲“ Tic Tac Toe”的语言,而不是“ save”,“ commit”或“提取[ X ]”。您可以将这些测试保存在交互测试或网关本身中。