业务逻辑是否可能不会潜入视图?


31

在过去的三年中,我已经为多个Web应用程序项目进行了开发,无论是个人的还是工作的,我似乎都无法弄清楚是否有可能至少某些业务逻辑没有出现在应用程序的视图层中。

在大多数情况下,会出现类似“如果用户选择了选项x,那么应用程序必须使他能够提供y的信息,否则,他/她应该提供信息z”之类的问题。或执行一些AJAX操作,该操作应将一些更改应用于模型,但除非用户明确要求,否则不要提交更改。这些是我遇到的一些最简单的问题,我无法弄清楚如何避免视图中的复杂逻辑。

我读过的大多数有关MVC的书通常都展示一些非常琐碎的示例,例如CRUD操作,它们仅更新服务器上的数据并显示它们,但在大多数功能丰富的应用程序中,情况并非如此。

是否可以实现完全没有业务逻辑的视图?


2
看一下MVC派生MVP和MVVM(请参阅en.wikipedia.org/wiki/Model_View_Presenteren.wikipedia.org/wiki/Model_View_ViewModel),它们可能就是您想要的。
布朗

相关(可能是重复的):从用户界面解耦类
t 2014年

2
该视图是数据和逻辑的外部可见显示。视图不提供业务逻辑是不可能的。或者您是说视图中不应包含任何代码?您当然可以创建仅HTML视图。
BobDalgleish 2014年

您可能会研究模板动画;尽管这可能不会消除视图层中的所有逻辑,但看起来应该可以更好地分离事物。
保罗

我认为一个更好的问题是视图数据污染模型是更好还是包含与业务逻辑相关的视图逻辑呢?那是更现实的情况。您的问题本质上是提倡污染模型以支持视图,因为这将是完成您所要询问的唯一方法。
Dunk 2014年

Answers:


22

是否可以实现完全没有业务逻辑的视图?

我发现这是一个看似很难回答的问题。(发人深省的问题!)

从理论上讲,是的,取决于我们定义的业务逻辑。在实践中,严格分离变得困难得多,甚至可能是不希望的。

关注点分离是考虑构建软件的一种好方法:它为您提供了有关在何处放置代码的想法,并为维护人员提供了在何处查找代码的好主意。我会争辩说,如果没有关注点的分离,人们基本上不可能构建有效的软件。我们需要这个。

但是,与所有事物一样,也需要权衡取舍。出于其他原因,最佳概念位置可能不是最佳位置。也许您的Web服务器上的负载过多,所以您需要在网页上添加一些javascript,以在输入错误到达服务器之前捕获容易的输入错误;现在您已经有了一些业务逻辑。

没有业务逻辑,视图本身就没有任何价值。为了有效地使用和显示(隐式或显式),视图将了解其背后正在进行的业务流程。我们可以限制该知识量,也可以封存一部分知识,但是实际考虑通常会迫使我们“打破”关注点分离。


2
The best conceptual location may not be the best location for other reasons:太棒了!!
Magno C 2014年

8

我通常这样做:如果用户选择了选项x,则视图调用

controller->OptionXChanged()

然后控制器在视图上启用y:

view->SetEnableInfoY(True) // suppose False=SetDisable

该视图将决定发生的情况通知控制器,而不进行任何决定。


+1。OP的琐碎问题通常会在非琐碎的应用程序中按以下方式处理
dev_feed

将这种逻辑放入控制器有两个问题:1)它使单元测试复杂化,并且不可能支持同一数据的多个视图。
凯文·克莱恩

4

我怀疑您描述的示例是否真的是业务逻辑。您描述的示例是可以在系统上执行的操作。您选择将其呈现给用户的方式可能使您看起来好像在视图中执行业务逻辑。

从“查看”有利位置来看,它仅向系统提供InfoY或InfoZ。仅仅因为您的UI实施基于操作员的选择进行了一些动态更新(即,启用InfoY或InfoZ)并不能使功能业务逻辑。它实际上是视图实现逻辑。您完全可以简单地让操作员选择输入InfoY或InfoZ,而无需全部启用。在这种情况下,您是否仍将其视为业务逻辑?如果不是,则同样适用于动态启用/禁用信息字段。

提交示例也是如此。这是系统正常运行所需的2个单独操作。您的视图必须能够启动适当的操作以执行所需的功能。知道如何使用您的系统是否意味着业务逻辑正在泄漏?我可以看到有人会说“是”,但是如果您这样认为,那么现实是,就不会存在将业务逻辑与任何事物分开的事情。您必须知道系统在做什么/使用什么来完成有意义的事情。否则,创建一个可与所有可能的MVC应用程序一起使用的通用视图和控制器将很容易。我们知道这是不可能的。

最重要的是,我认为您对业务逻辑的定义与其他定义不同。


1

我以这种方式工作(Struts2 +休眠):

我的Struts操作仅负责在Web浏览器上显示信息。没想

用户->操作->服务->存储库->数据访问

要么:

我想看->如何看->怎么做->如何获得->从哪里获得

因此,在第一层(视图)中,我有类似以下内容:

public String execute ()   {
    try {
        CourseService cs = new CourseService();
        Course course = cs.getCourse(idCourse);
    } catch (NotFoundException e) {
        setMessageText("Course not found.");
    } catch (Exception e) {

    }
    return "ok";
}

如您所见,我的“观点”没有思考。它要求提供特定课程的服务(用于管理课程)。该服务可以做更多的事情,例如报告,搜索等等。结果始终是列表或特定对象(如示例)。这些服务是真实的机器,可以应用规则并访问存储库(以管理数据)。

因此,如果将我的服务,存储库和DAOS放在不同的库中,则即使在基于文本的程序或基于Windows的桌面系统中也无需更改,也可以使用它。

该服务知道该怎么做,但不知道如何显示。该视图知道如何显示,但不知道该怎么做。与服务/存储库相同:服务发送和请求数据,但不知道数据在哪里以及如何获取。存储库将原始数据“组成”到buisines对象,以便服务可以使用。

但是存储库对数据库一无所知。DAO与数据库类型(MySQL,PostgreSQL等)有关。

如果要更改数据库,则可以更改DAO,并且它一定不会影响上层。如果要更新数据管理,则可以更改存储库,但这不能影响DAO和上层。如果您想更改逻辑,则可以更改服务,但这一定不能弄乱上方或下方的层。

您可以更改任何可见的内容,甚至可以更改技术(Web,桌面,文本),但这绝不能暗示以下任何内容。

业务逻辑是服务。但是如何与之互动是有待观察的。现在显示什么按钮?用户可以看到此链接吗?认为您的系统是基于控制台的程序:您是否必须拒绝错误的用户选择#> myprogram -CourseService -option=getCourse -idCourse=234或阻止他按下键来编写此命令?

在基于Web的系统(Struts + JavaEE)中进行交谈我有一个单独的GUI控制器程序包。在视图操作中,我给了登录用户,而类给了我按钮(或我想要的任何界面元素)。

                <div id="userDetailSubBox">
                    <c:forEach var="actionButton" items="${actionButtons}" varStatus="id">
                        ${actionButton.buttonCode}
                    </c:forEach>
                </div>

private List<ActionButton> actionButtons;

切记不要将其保留在服务范围之外。这是VIEW资料。将其保留在Struts动作中。任何接口的交互都必须与真实的业务代码完全分开,因此,如果您移植系统,将很容易削减不再需要的内容。


1

在大多数情况下,会出现类似“如果用户选择了选项x,则应用程序必须使他能够提供y的信息,否则,则s /他应该提供信息z”的问题。

那是模型的逻辑,而不是视图。它可能是专门为支持UI而创建的“视图模型”,但仍然是模型逻辑。控制顺序为:

  • 控制器为视图事件附加处理程序
  • 视图为模型事件附加处理程序
  • 用户选择选项X。
  • 该视图引发事件“选择了选项X”
  • 控制器接收事件并调用model.selectOptionX()
  • 模型引发事件“模型状态已更改”
  • 该视图接收模型更改事件并更新视图以匹配新状态: inputY.enable(model.yAllowed()); inputZ.enable(model.zAllowed());

UI View Controller Model |.checkbox X checked.> | | | | | .. X selected ...>| | | | |-----> set X ------->| | | | | | |< .............state changed ............| | | | | | |-------------- Get state --------------->| | | | | | |<----------- new state ------------------| | <-- UI updates ------| 这是经典的MVC模式。可以完全测试与UI分离的模型逻辑。控制器和视图非常薄,易于测试。

===回应扣篮===

UI MVC模式中的模型(通常)不是业务对象模型。它只是UI状态的模型。在桌面应用程序中,它可能包含对多个业务模型的引用。在Web 2.0应用程序中,它是一个Javascript类,用于保存UI状态,并通过AJAX与服务器进行通信。能够编写UI状态模型的自动单元测试非常重要,因为这是发现大多数UI错误的地方。视图和控制器应为非常薄的连接器。


1
我想这全都归结为您认为MVC的定义。此版本绝对遵循对MVC的非常非常严格的解释。问题在于,这种严格的解释很少在现实生活中提供有用或可维护的系统。原因是几乎每当您想出新的UI元素/做某事的方式都必须更改模型时。然后,该模型变得杂乱无章,只有与UI相关的无用属性。这些与您尝试构建的应用程序无关,而仅与您想要向操作员呈现数据的方式有关。坏!
2014年

凯文(Kevin),请将您的回复放在评论框中,以便我们轻松答复。我同意你的看法。没有任何类型的结构就不可能维护接口(UI)信息,但是“ MODEL”命名法可能会造成混淆。我更喜欢在另一个可互换的程序包中管理UI内容,以轻松实现@Dunk所说的。看我的答案。
Magno C 2014年

@MagnoC:我编辑了他对Dunk的回答,因为我认为添加的文字可以改善答案。这就是该网站的主题:问题和答案。模型是一个相当笼统的术语,在MVC模式中,它表示“ UI状态模型”。
凯文·克莱恩

0

业务逻辑更像If X then return InfoType.Y,则UI将根据域返回的结果显示字段。

// Controller method pseudocode
option changed routine

    get selected option

    get required info type from domain routine based on selected option

    display fields based on required info type

如果UI需要业务逻辑,则将选择委托给域。用户界面将仅根据决定进行操作。


0

如果用户选择了选项x,则应用程序必须使他能够提供y的信息,否则,则s /他应该提供信息z“。

有些输入具有基于条件的所需值。在大多数GUI环境中,如何处理输入(尤其是时序)有很多选择。所选选项(在本例中为x)需要进行处理,因此将其发送到控制器。用户离开输入字段时发送。等到他们单击另一个对象或点击保存。与业务逻辑无关。控制器将以一种或另一种方式做出决定,并需要告知视图“ y是必需的”。

从业务逻辑的角度来看,视图如何解释或实现这一点并不重要。设为必填字段。弹出窗口或发射大炮,并告诉用户输入y或固执己见,直到可怜的用户找出答案后再让他做任何事情。

只是想想,所有这一切都可能发生了,因为控制器试图保存并且没有为数据库中的必填字段输入值,并且纯粹是在响应数据库错误。就视图而言,这无关紧要。

诸如输入的必需值或限制值之类的东西可以在很多地方处理。如果在视图中“仅”解决该问题,那么当可以有多个用户界面时,许多开发人员会认为这是一个问题。这就是为什么无需大量用户界面甚至数据库就可以创建和测试业务逻辑的原因。您甚至不必拥有网站。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.