在MVC中,在控制器类中具有私有的非动作功能是否被认为是一种好习惯?


10

有时,控制器类中的动作函数可能变得庞大而令人讨厌,使用许多行代码可以简单地控制从模型到视图的数据流。在某些时候,这些巨大的功能完全无法跟踪良好代码的基本原理,即仅做一件事,体积小,可读性强且易于管理等。

将这些巨大的动作函数分解为控制器类中较小的私有函数是否被视为一种好习惯,还是这种优化的需求意味着我们宁愿将它们添加到模型中?

我赞成在控制器中将较小的函数设为私有,以便它们与操作相关,但我听到有人争辩说,在模型变得庞大而笨拙时,控制器最好应该是简单的。只是想知道哪种方法是最可取的。

Answers:


16

可能不是最好的类比,但是,对控制器的思考方式与对蜘蛛网的思考方式相同。它的唯一工作是捕获苍蝇(请求)以使蜘蛛(底层)消化。该网可以捕获并容纳较小或较大的苍蝇(模型)。蜘蛛网的作用不是消化猎物,尽管它可以用于此目的。纤网越薄越干净,蜘蛛就越容易谋生。

您可以将某些相同的逻辑应用于您的MVC应用程序。您描述的庞大而讨厌的功能很可能是模型的行为,它们应该属于模型(请注意,模型不仅是在视图中显示的对象)。如果模型的行为发生变化,则应更改模型,而不是处理该模型的控制器。

同样,将它们作为私有方法保留在控制器中只会使它混乱,并且难以维护。这也为坏习惯铺平了道路,因为参与开发的其他人会很想这样做,因为他们之前在项目中已经看到过这样做。


+1为创意类比。:)您提出了一个有趣的观点。特别是在养成不良习惯上。谢谢。
大卫“秃头姜”

8

我能给出的最佳答案是引用罗伯特·马丁(Robert Martin)的一本好书,即“清洁代码”,我强烈建议对此主题有兴趣的人:

功能的第一个规则是它们应该很小。第二条规则是它们应该小于该值。

不能说得更好。同一本书的另一篇引文也很适用:

函数应该做一件事。他们应该做好。他们只能这样做。

将代码拆分为更多函数时,必须为这些函数提供有意义的名称,从而可以大大提高代码的可读性。不用说,所有不打算在类外部使用的函数都应该是私有的,因此您可以通过继承轻松地重用代码。

如果您的控制器现在具有太多功能,则表明它可能执行了太多操作。然后,您可以将其拆分为几个独立的部分,或尝试将其他函数移至模型,如另一个答案中所述。同样,如果遵循非经典的MVC风格(允许视图具有某种逻辑),则可以在适合的地方放置一些函数。


1
我认为将业务逻辑放入视图不是“非经典MVC”,而只是“不良MVC”。显然,您在视图中需要基本的控制结构,但是它们应该与用户/ UI问题(而不是域/业务问题)保持一致。视图中的实际功能非常可怕。
亚罗诺(Aaronaught)2013年

1
@Aaronaught我对“某些逻辑”含糊不清,我想到的是例如Backbone.js库,您可以在其中放置用户事件和函数以在视图中处理它们。在经典MVC中,这是控制器的工作。但是,这可能不切实际,因为每次UI更改时都需要同时调整View和Controller。通过将UI处理程序功能放在视图中,您只需要调整视图。那只是我的主观看法-我错过了什么吗?
Dmitri Zaitsev

1
仅仅因为某些东西在客户端交付并不意味着它在逻辑上是视图的一部分。当然,数据绑定在视图中,但是Backbone本身是MV *框架(MVC的种类,MVP的种类,两者都不是),并且应该相应地组织客户端脚本。否则,您只是在入侵。
Aaronaught

0

在MVC中,我尝试确保控制器尽可能“薄”,并且我的模型也尽可能哑。

所需的逻辑和帮助程序功能将放入单独的独立帮助程序类中。这也使我的测试变得容易得多(您正在测试..正确吗?:D)测试控制器非常困难,每当您尝试创建控制器实例来进行测试时,您都必须考虑HTTP上下文和伪造http this and that,虽然很痛苦,但是故意造成痛苦。您需要所有这些东西,因为控制器是如此紧密地链接到HTTP和Web。它是您的Web应用程序的入口点。

逻辑和辅助功能与网络无关。它们完全与环境无关(或者应该是)。仅此而已就可以告诉您他们不在同一个地方。另外,如果您将所有应用程序逻辑紧密地与Web或特定的Web实施联系在一起,那么您永远都无法将其带走。

我们使用所有数据库实体(不是我们的mvc模型,我们实际的数据库实体),我们的存储,我们的帮助程序类以及我们单独的dll中的逻辑开发了MVC网站。我们只有每个人都有一个网站,但是无论如何我们都是这样做的。

几个月前,我们被要求创建一些与我们的边缘系统相关的桌面应用程序。这很容易完成,因为我们所有经过测试的代码都可以轻松地重复使用。如果我们将代码推送到我们的Web项目中或放入我们的控制器中,我们将永远无法做到这一点。


2
MVC中的模型是唯一不应被认为愚蠢的层。如果智能不在模型中,并且不在控制器中,那么它们在视图中的什么位置?控制器也应该不难测试;使用DI和假冒/伪造来促进单元测试的能力是MVC与其他框架相比的吸引力之一。我的大多数控制器测试都在5行以下。
亚罗诺(Aaronaught)2013年

我会在逻辑中使用“ helper”类,而不是在逻辑中渗透模型。您将在模型中放入哪种逻辑?它知道如何加载并保存自身吗?我同意伪造/存根很容易,但这并不是增加控制器的借口。
太空人2013年

我觉得这个答案很好,但是措辞不正确..或者也许是不同的术语。
西蒙·怀特海德2013年

3
“帮助程序”类不是体系结构元素。它们是M,V或C的一部分。如果您不确定哪个,那么这些帮助者将缺乏凝聚力。“ helper”一词也紧随其后,带有“ handle”,“ do”,“ perform”和可怕的Manager
亚罗诺(Aaronaught)2013年

@SimonWhitehead:大多数答案都很好,但许多答案不正确。不幸的是,这是在引起对“模型”含义的误解,或者建议将关键的业务逻辑置于模型之外。拥有无数“帮助者”维护MVC网站时,我一直感到非常高兴,因为它们令人恐惧。
亚伦诺特,2013年

-2

除了Dmitri Zaitsev和spaceman的出色答案之外,我不知道以下内容是否也适用于PHP:由于缺乏自动测试的可能性,您应尽量避免使用私有方法。

是的,您也可以使用元编程或依赖项注入来测试私有方法,但您不应该这样做,因为它会对代码的可读性产生巨大影响。

永远记住KISS原则:保持简单,愚蠢。


5
不是避免使用私有方法的好理由,并且与MVC架构也没有任何关系。您不要尝试测试私有方法,而应该对公共方法进行测试。如果您不能涵盖它们,那么这表明您的课程太复杂了,需要重构。这并不意味着您不应该拥有私有方法,或者(我衷心希望这不是您真正的意思)应该公开它们。
亚伦诺特,2013年
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.