简洁的体系结构:控制器和演示者应该始终是单独的类,还是可以相同?

问题描述

我了解“清洁体系结构”中控制器和演示者的目的,而并不是说用例应该调用控制器来呈现数据(或者至少知道它必须调用控制器),但是假设我们已通过以下方式设置了我们应用程序的界面部分:(伪代码

interface OutputPort {
    + present(response: Response)
}

interface InputPort {
    + run(data: inptuData)
}

class UseCase implements InputPort  {
    - presenter: OutputPort

    + run(data: InputData) {
        ...
        response: Response = ...
        this.presenter.present(response)
    }
}

在这种情况下,我们的UseCase完全不了解外部圈子。它实现了InputPort接口以公开API以让外部圈子调用他,并且它需要一个OutputPort(在Presenter中为Cleaner),将用于传递和“显示”结果。

所以现在通常我们有:

class Presenter implements OutputPort {
    + present(response: Response) {
        ...
    }
}

class Controller {

    - presenter: Presenter;

    + executeUseCase() {
        data: InputData = ...
        useCase: UseCase = UseCase(presenter)
        useCase.run(data)
    }
}

为什么我不能这样做?

class Controller implements OutputPort {

    + present(response: Response) {
        ...
    }

    + executeUseCase() {
        data: InputData = ...
        useCase: UseCase = UseCase(this)
        useCase.run(data)
    }
}

它仅用于SRP还是有其他原因?假设控制器和Presenter足够短并且使用相同的对象,在代码需要拆分之前将两个实现维护在一个类中是否值得?

我的意思是,每次我们谈论Clean Architecture时,我们通常会想到Web应用程序或移动应用程序,在这些应用程序中,与外部世界的交互始终是用户和UI,因此在这种情况下,很明显,应维护两者分开上课是有好处的。 但是,假设外部参与者是一个外部API,可以发送信号通知我们执行某项操作,并且应该根据执行的操作来接收信号。 在这种情况下,如果我创建一个单独的Controller和Presenter,则应同时引用外部API:给控制器以让他监听信号并触发用例,给Presenter以便向他发送信号。用例末尾的API。 考虑到这种交互的简单性,不是最好让控制器和演示者是同一类(尽管仍然实现一个单独的接口以允许将来拆分),以避免在应用程序中传播外部API的知识吗?

解决方法

首先,在这两种情况下,您的依赖项均符合原始架构。

假设控制器和Presenter足够短并且使用相同的对象,在代码需要拆分之前将两个实现维护在一个类中是否值得?

您可以这样做,但是如果将两者分开,则可能更易于测试。因为当您要测试演示者逻辑时,不需要设置控制器的依赖关系。

我的意思是,每次我们谈论Clean Architecture时,我们通常会想到Web应用程序或移动应用程序,在这些应用程序中,与外部世界的交互始终是用户和UI,因此在这种情况下,很明显,应维护两者分开上课是有好处的。但是,假设外部参与者是一个外部API,可以发送信号通知我们执行某项操作,并且应该根据执行的操作来接收信号。

如果使用演示者,通常会处理用户界面,但是可以看到演示者的概念更为笼统。

如果控制器由另一个外部系统调用。该系统还需要某种格式的数据。也许是二进制格式,但也许是XML或JSon。在所有情况下,您都必须处理用例的输出向外部呈现的转换。因此,演示者不一定是UI组件。

因此,术语“展示者”,“序列化器”或“格式化器”都基于相同的概念。而且,如果您将它放在一个单独的类中,则可以轻松对其进行测试。

这是我绘制的图表,用于显示如何在邮件环境中应用干净的体系结构。例如。 JMS。如果外部绝对不是用户界面,那将是一个体系结构。当然,MessageProducer应该使用演示者或序列化器或任何您称为它的东西来创建传出消息。这是一幅较旧的图纸。也许我会改变一段时间。

Clean Architecture in a messaging environment

只要遵守干净架构的依赖关系规则,就可以轻松替换用例向外部展示的方式。