Shiny: MVC 架构

创建于 2013-09-30  ·  5评论  ·  资料来源: rstudio/shiny

我可以按照模型视图控制器模式使用 Shiny 开发的应用程序吗?
例如...
我的观点——> HTML5/CSS/JS。
我的模型和控制器使用 Shiny 框架用 R 语言编程。
像这样在某些配置文件中映射操作。
{
网址:/mysite/path/action1?id=data1&n=1000
控制器:闪亮控制器
行动:行动1
}

我有文件:
闪亮控制器.r

Action1 = 函数(id,n){
...
}

最有用的评论

因此,这值得进行更广泛的讨论,即 Shiny 作为 Web 应用程序框架是如何定位并适应 Web 应用程序世界的其他部分的。 @jcheng5 ,我觉得在某些时候,我们应该按照这些思路写一些东西……我只是想在这里尝试我的不完全格式良好的两美分。

两个框架

直到最近,MVC(以及随后的关注点分离概念,SoC)一直是最流行的 Web 应用程序框架。 如今,我认为传统的命令式 MCV 框架与 ReactJS(由 Flux/Redux 补充)和 Shiny 的反应性等东西使之成为可能的更具声明性、功能性的替代方案在很大程度上是一种联系。

对于 Shiny,我们主要决定致力于反应性和声明性渲染风格,因为我们觉得这更适合我们用户想要创建的那种应用程序。 有一些例外,比如全新的insertUIremoveUI函数,它们完全脱离了正常的反应式工作流程并使用 100% 命令式风格。 尽管如此,Shiny 仍有 99% 的反应性。

在反应性世界中,控制器变成了黑盒

在传统的 MVC 中,控制器是必不可少且明确的:您必须指定在收到用户请求时要执行的操作以及要调动哪些资源来执行模型中概述的必要任务。 在响应式世界中,控制器变成了一个黑盒:您不再需要担心 DOM 的命令式突变序列。 该框架会为您解决这个问题。 您只需要指定如何在给定特定状态的情况下呈现视图。 当该状态发生变化时,框架将计算最有效的突变集,将你从你所在的地方带到你想去的地方。 因此,控制器实际上对应用程序作者隐藏,他们可以放心——给定正确的渲染“配方”——框架知道如何处理任何用户请求。

这导致代码更可预测。 您只需要知道应用程序在任何给定时间的状态——您不必担心一系列命令式语句以及所有这些 DOM 突变如何转换为新状态。

单向数据绑定

Shiny 具有与 Flux 的单向数据流类似的单向数据绑定。 另一方面,MVC 通常使用双向数据绑定(模型和视图之间),这不一定能很好地扩展。 您最终可能会遇到难以发现的级联和嵌套操作,这再次降低了代码的可预测性和调试难度。 由于这种差异,“模型”的概念在响应式世界中并不像在命令式或 MVC 世界中那样相关或重要。 我觉得“渲染说明”或“配方”对反应性更有意义。

但是如果你想扩展这个术语,你可以说模型是放置在服务器代码中render函数中的任何东西。 当该代码更改时,这会反映在 UI 中(例如,当input$z - 在render函数中使用 - 更改值时,应用程序将重新呈现相应的 UI 元素对于那个render函数)。 但是您无法根据新 UI 更新render函数的内容。

对于 Shiny 来说,这意味着大致如下。 在您的服务器代码中,您可以(并且应该)拥有:

output$y <- renderXXX({ 
  ## code that uses input$z 
})

但你永远不能拥有:

input$z <- renderXXX({ 
  ## code that uses output$y 
})

因此,输入通知输出,而不是相反。 如果你需要动态输入,你必须使用uiOutputrenderUI来保证你在响应式框架中的安全,或者(如果你知道你在做什么)命令式的insertUIremoveUI

重新审视 SoC

SoC 是一个在 MVC 世界中很有意义的概念。 它在反应性世界中不太相关。 例如,如果你想对此严格一点,你可以说 ReactJS 违反了 SoC,因为同一个组件通常既控制状态又渲染状态。 但这两个框架如此不同,以至于这种比较似乎有点不公平。 此外,您实际上可以提出这样的论点:反应式世界比 MVC 世界做得更好,因为后者围绕三个关注点构建 SoC:模型、视图和控制器。 在反应式世界中,可以用更广泛的术语定义关注点——您可以创建一个模块化组件来解决您确定的任何关注点。

您仍然可以尝试遵循 Shiny 中的传统 SoC,方法是严格在ui函数中执行所有视图,并严格在server函数中执行所有建模。 如果您使用 htmlTemplates,您可以更加明确。 _然而_,正如上面所暗示的,我认为在现代网络应用程序世界中被证明更相关的概念与其说是 SoC,不如说是模块化或组件化——即封装每个功能单元并在必要时重用它。 Shiny 通过模块实现了这一点。

其他资源

我推荐这个来自 Facebook Developers 的视频,它描述了他们在 MVC 中发现的缺点以及如何创建 Flux 和 React 来解决这些问题。 虽然与 Shiny 存在明显差异,但它很好地概述了两种不同的方法。

所有5条评论

在当前的设计下,我认为 View 是ui.R ,Model 是server.R ,而 Controller 嵌入在ui.R中,并由input参数表示传递给server.R

您想要的可能是访问客户端数据: http: //rstudio.github.io/shiny/tutorial/#client -data 然后由您来定义您想要的任何控制器。 不确定这是否回答了你的问题。

我的观点是模型、视图和控制器都在服务器中。

视图是 output$ 和 input$

控制器是反应者和观察者。

-亚历克斯·布朗

2013 年 9 月 30 日下午 2 点 30 分,谢益辉通知@github.com 写道:

在当前的设计下,我认为 View 是 ui.R,Model 是 server.R,而 Controller 是嵌入在 ui.R 中,由传递给 server.R 的输入参数表示。

您想要的可能是访问客户端数据: http: //rstudio.github.io/shiny/tutorial/#client -data 然后由您来定义您想要的任何控制器。 不确定这是否回答了你的问题。


直接回复此邮件或在 GitHub 上查看。

好吧,我没有CS背景,所以我可能会胡说八道:)

是的,你不支持MVC。 适当的关注点分离意味着您的业务逻辑将与 VIEW 分开,因此“ui.r”不能保存 VIEW 和 CONTROLLER; 那没有意义。

因此,这值得进行更广泛的讨论,即 Shiny 作为 Web 应用程序框架是如何定位并适应 Web 应用程序世界的其他部分的。 @jcheng5 ,我觉得在某些时候,我们应该按照这些思路写一些东西……我只是想在这里尝试我的不完全格式良好的两美分。

两个框架

直到最近,MVC(以及随后的关注点分离概念,SoC)一直是最流行的 Web 应用程序框架。 如今,我认为传统的命令式 MCV 框架与 ReactJS(由 Flux/Redux 补充)和 Shiny 的反应性等东西使之成为可能的更具声明性、功能性的替代方案在很大程度上是一种联系。

对于 Shiny,我们主要决定致力于反应性和声明性渲染风格,因为我们觉得这更适合我们用户想要创建的那种应用程序。 有一些例外,比如全新的insertUIremoveUI函数,它们完全脱离了正常的反应式工作流程并使用 100% 命令式风格。 尽管如此,Shiny 仍有 99% 的反应性。

在反应性世界中,控制器变成了黑盒

在传统的 MVC 中,控制器是必不可少且明确的:您必须指定在收到用户请求时要执行的操作以及要调动哪些资源来执行模型中概述的必要任务。 在响应式世界中,控制器变成了一个黑盒:您不再需要担心 DOM 的命令式突变序列。 该框架会为您解决这个问题。 您只需要指定如何在给定特定状态的情况下呈现视图。 当该状态发生变化时,框架将计算最有效的突变集,将你从你所在的地方带到你想去的地方。 因此,控制器实际上对应用程序作者隐藏,他们可以放心——给定正确的渲染“配方”——框架知道如何处理任何用户请求。

这导致代码更可预测。 您只需要知道应用程序在任何给定时间的状态——您不必担心一系列命令式语句以及所有这些 DOM 突变如何转换为新状态。

单向数据绑定

Shiny 具有与 Flux 的单向数据流类似的单向数据绑定。 另一方面,MVC 通常使用双向数据绑定(模型和视图之间),这不一定能很好地扩展。 您最终可能会遇到难以发现的级联和嵌套操作,这再次降低了代码的可预测性和调试难度。 由于这种差异,“模型”的概念在响应式世界中并不像在命令式或 MVC 世界中那样相关或重要。 我觉得“渲染说明”或“配方”对反应性更有意义。

但是如果你想扩展这个术语,你可以说模型是放置在服务器代码中render函数中的任何东西。 当该代码更改时,这会反映在 UI 中(例如,当input$z - 在render函数中使用 - 更改值时,应用程序将重新呈现相应的 UI 元素对于那个render函数)。 但是您无法根据新 UI 更新render函数的内容。

对于 Shiny 来说,这意味着大致如下。 在您的服务器代码中,您可以(并且应该)拥有:

output$y <- renderXXX({ 
  ## code that uses input$z 
})

但你永远不能拥有:

input$z <- renderXXX({ 
  ## code that uses output$y 
})

因此,输入通知输出,而不是相反。 如果你需要动态输入,你必须使用uiOutputrenderUI来保证你在响应式框架中的安全,或者(如果你知道你在做什么)命令式的insertUIremoveUI

重新审视 SoC

SoC 是一个在 MVC 世界中很有意义的概念。 它在反应性世界中不太相关。 例如,如果你想对此严格一点,你可以说 ReactJS 违反了 SoC,因为同一个组件通常既控制状态又渲染状态。 但这两个框架如此不同,以至于这种比较似乎有点不公平。 此外,您实际上可以提出这样的论点:反应式世界比 MVC 世界做得更好,因为后者围绕三个关注点构建 SoC:模型、视图和控制器。 在反应式世界中,可以用更广泛的术语定义关注点——您可以创建一个模块化组件来解决您确定的任何关注点。

您仍然可以尝试遵循 Shiny 中的传统 SoC,方法是严格在ui函数中执行所有视图,并严格在server函数中执行所有建模。 如果您使用 htmlTemplates,您可以更加明确。 _然而_,正如上面所暗示的,我认为在现代网络应用程序世界中被证明更相关的概念与其说是 SoC,不如说是模块化或组件化——即封装每个功能单元并在必要时重用它。 Shiny 通过模块实现了这一点。

其他资源

我推荐这个来自 Facebook Developers 的视频,它描述了他们在 MVC 中发现的缺点以及如何创建 Flux 和 React 来解决这些问题。 虽然与 Shiny 存在明显差异,但它很好地概述了两种不同的方法。

此页面是否有帮助?
0 / 5 - 0 等级