ReactiveX,关于移动应用程序架构和层

时间:2017-11-03 11:19:36

标签: ios swift mvvm rx-swift reactive

我正在学习Rx(特别是RxSwift),我对架构,层和边界有疑问。

我习惯于分层架构(数据,域名,演示文稿),通常是在MVP或VIPER上。对于这个项目,我使用的是MVVM,这是Reactive app的推荐架构。这些是我目前的合作者:

**** Presentation ******************************************

                 ________________________
                |                        |
                |   GameViewController   |
                |                        |
                |      ____________      |
                |     |            |     |
                |     | BoardView  |     |
                |     |____________|     |
                |                        |
                |________________________|
                             |
                             |
                            \|/
                 ________________________
                |                        |
                |     GameViewModel      |
                |________________________|
                             |
**** Domain **************** | *****************************
                            \|/
                 ________________________
                |                        |
                |     GameController     |
                |________________________|

当用户点击(移动)时,BoardView会发出GameViewController正在观察的事件,该事件调用GameViewModel中与{{1}进行通信的方法检查移动是否正确,然后发出链中每个人观察到的另一个事件,最后GameController根据移动的正确性绘制其内容。

我的问题是,这个流程是否正确?我是否必须坚持这种做事方式,或者有一种更适合的反应方式?例如,也许BoardView可以直接与视图模型对话而不涉及视图控制器,并且没有边界破坏也没有违反规则"。

我在Rx更好的架构方面有点迷失,MVVM很简单但是为了使它成为SOLID你必须创建更多的协作者,然后可观察链可能有点过度设计。

任何帮助都将非常感谢!谢谢:))

2 个答案:

答案 0 :(得分:1)

在编写良好的反应式应用程序中,您的逻辑将倾向于封装在许多无状态(静态)函数中而不是对象中。从而使您的代码更具说明性。

作为一个例子,你的GameViewModel应该接受它将观察的许多输入可观察量,并为要订阅的视图产生许多输出可观察量。

struct MyViewModel {
    let output: Observable<OutState> 
    init(input: Observable<InState>) {
        output = input.map {
            // transform input state into output state
        }
    }
}

在上面注意,变换是纯函数。还要注意,对象本身是多余的。它可以很容易地成为一种功能:

func myOutput(input: Observable<InState>) -> Observable<OutState> {
    return input.map {
        // transform input state into output state
    }
}

那个变换块当然可以是一个函数。

func transform(in: InState) -> OutState {
}

这很容易测试,并自然地封装了应用程序的特定用例。

答案 1 :(得分:0)

通常,当您使用数据驱动架构(例如MVVM)时,您有多个Service对象可以满足您的业务逻辑。在Rx世界中,您订阅了您的服务和服务,将DTOs推送到您将其映射到ViewModel的控制器中。如果你要SOA,我真的建议你调查MVVM,因为ViewModel只是DTO的装扮者,可以被不同的观点接受。您的业​​务逻辑应该包含在服务中。

Rx只是推送界面及其随时间变换的集合,它允许您的对象更加封装和自给自足。当控制器决定时,Rx方法允许您的对象在业务逻辑需要时提供该数据,而不是提取数据。我不认为在使用Rx时,可以在MVVMVIPER内为每个业务逻辑方案定义100%拟合规则。只需使用常识,看看你的对象何时将信息推送到接收者而不是在接下来的时间拉动它。

旁注:我真的建议您远离任何数据驱动对象定义方法(无论是MVVM还是VIPER)。 Here is why