75

哇,戏剧!框架有很多静态方法。在我上学的地方,我们被告知永远不要使用任何静力学,但 Play!像没有明天一样使用它。这样可以吗?如果是这样,为什么?

我们(我和 7 个人)计划使用 Play!涉及 Web 应用程序的项目的框架。我们决定使用 Play!因为看起来很有趣,我们所有人都已经了解 Java,而且作业非常难,所以我们想专注于实际作业,而不是学习如何用不同的语言编程。

然而,我们总是被告知,永远不要在我们开发的任何 Java 程序中使用“静态”,但是当我查看 Play!...嗯...大约一半的方法是静态的。</夸张>

我想,至少,我们可以使用单例对象(通过使用 Scala,例如 ^^)来对我们的项目进行编程,但我非常关心框架本身实际上有多少静态变量。

那么,我应该担心这个吗?玩的方式!开发人员对其进行了编程,以便所有这些静态不会造成问题?

(例如,该线程对为什么不惜一切代价避免使用静态成员进行了咆哮。)

4

14 回答 14

95

Play 仅在有意义时才使用静态方法:

  • 在控制器层,因为控制器不是面向对象的。控制器充当 HTTP 世界(即无状态,基于请求/响应)和完全面向对象的模型层之间的映射器。
  • 在工厂方法的模型层中,例如 findAll()、count()、create(),它们当然不依赖于任何特定实例
  • 在一些提供纯粹实用功能的 play.libs.* 类中
于 2011-03-04T12:31:36.020 回答
34

Play framework 并不能很好地证明何时使用静力学合适,也不能证明你的老师错了。Play 是一种作弊,解决了 Java 语言之外的静态问题。

关键问题是您必须并行处理多个 HTTP 请求,并且静态字段是“全局的”。因此,对于某些事情,每个线程需要一个实例(或者更好的是,每个 HTTP 请求一个实例),但其中一些事情是由 Play 中的静态方法返回的。之所以有效,是因为 Play!大量使用ThreadLocal-s,因此它解决了 Java 语言之外的静态问题。但这还不是全部。有人说控制器方法是静态的。当然,但是在纯 Java 中会很不方便,因为如果没有某种前缀(例如req.in ),您将无法访问特定于请求的数据req.session,然后您仍然必须req从某个地方获取,例如作为静态控制器方法的参数,这就更麻烦了。然而在 Play 你可以直接写session就像,它们只是静态字段。那是因为 Play 使用字节码检测将所有这些静态字段引用更改为更智能的东西。同样,Java 语言之外的解决方案。最后那些不是静态字段。

所以,一般来说,避免非最终静态。不过,玩会为你带来魔力,所以在这种情况下不要害怕它们。

于 2011-08-04T19:15:14.037 回答
15

从一个非常简短的角度来看,我会说这是有道理的:网络请求是无状态的,所以没有对象可以接收请求(=方法)。因此,将诸如“/articles/archive?date=08/01/08&page=2”之类的 URI 映射到调用的静态方法archive(),我猜,您的应用程序类是有意义的。

于 2011-03-04T11:12:33.250 回答
8

编辑 现在在 Play 2.4 中,注射是自动完成的。因此,只需在文件中控制器路径的开头添加 @ 即可routes

GET     /                  @controllers.Application.index()

对于旧版本(2.1 到 2.3),您必须在 Global 类中覆盖 getControllerInstance,如Documentantion中所述。

于 2013-12-14T01:59:45.923 回答
5

与编程中的任何事情一样,永远永远不是正确的答案。就像往常一样。总是有例外,正确的答案总是“视情况而定”。

确实,在纯 OO(我完全赞成)中,静力学的空间很小。但有时它们只是有意义的,这也是事实。

经典的例子是实用方法。当然,如果我们可以将我们的abs()方法附加到 Integer 会更好。但我们不能;所以我们被困在Math.abs(int i).

我倾向于认为,当方法与实例本身无关时,将其设为静态是正确的。例如,在一个类Person中,您可以有一个方法,该方法获取人员列表,并返回今天过生日的人数。如果进行计算所需的数据是私有的(OO 纯粹主义者会理解 ;)),也许您只能在类本身中执行此操作,但该方法显然与单个 Person 实例无关。

另一件事是内部类。如果您不需要与包含类型的关系,您通常希望将它们设为静态。

我从没见过玩!但如果你说超过 50% 是静态的,那么我猜它可能设计得很糟糕。这也不例外。很多框架都是。不要让它让你失望。绝对不学习!
但如果它有效,您仍然可以使用它。

于 2011-03-04T12:11:20.227 回答
4

主要问题是静态方法只能访问其他静态方法和字段,这会导致“静态附着”,即静态方法必须通过公共静态字段与应用程序的其余部分(包含其协作者)会合,导致不灵活。

免责声明:我对“玩”了解不多!

于 2011-03-04T11:41:09.633 回答
4

静态控制器方法当然是 Play 关注的一个领域!框架,在做了一些测试之后,这是我不玩Play的主要原因!在项目中。您实际上可以在 FOSS 项目中 Play! 用来。很少或没有控制器测试。原因在于,使用静态方法,DI 变得困难。这是他们应该在 ASP.NET MVC 上花费更多时间的地方,从那里玩!已经有点灵感了。

通常你有一个这样的构造函数:

public HomeController( IService service ) {
   _service = service;
}
public Index() {
   var data = _service.getData();
   return View( data );
}

然后使用 DI 将 IService 实现注入到 Controller 中。关键是在您的测试中,您可以在运行 Controller 之前实例化 IService,然后根据您刚刚生成的 IService 测试结果。

在 Play 中,这变得非常困难。因此控制器单元测试变得困难。对我来说,这是一个重大问题。因此,我倾向于寻找除 Play 之外的其他框架!在 Java 世界中。哎呀,为什么不使用原始版本而只使用 JRuby 呢?

于 2012-10-29T12:36:46.843 回答
3

游戏中的静态方法主要用于控制器的动作方法。这些方法旨在从模型中获取必要的数据并将其公开给视图。

它们以某种方式对应于每个可能的 http 请求,并且就像那些 http 请求是完全无状态的一样。

在结构化编程中,一方面有过程,另一方面有变量,但在 OOP 范式中,你将过程和变量视为一个整体。

也就是说,您拥有带有实例方法(过程)和实例变量的对象。

但是控制器操作是无状态的,即它们从请求中获取所有变量(可能也从缓存中,但在这种情况下,您需要某种最终来自请求的会话 id)。所以控制器动作就像状态过程一样,这就是为什么它们不像模型那样特别适合 OOP 范式。

于 2011-03-05T05:12:24.700 回答
2

我想,至少,我们可以使用单例对象

Java 中的单例与使用全静态没有太大区别。也没有太多要存储的状态。我认为你不应该担心它。

那么,我应该担心这个吗?玩的方式!开发人员对其进行了编程,以便所有这些静态不会造成问题?

它不会。事实上,没关系。

于 2011-03-04T11:23:02.657 回答
1

我也对正在使用的静态方法的数量感到惊讶,但如果它工作正常,为什么不...

其实我不同意你老师的观点。

如果一个对象没有状态(即全局变量)但只包含示例方法,那么使用对象而不是静态方法不会给您带来任何好处。除非您打算稍后添加状态(不应该共享的状态),或者您正在使用接口并且希望能够轻松切换实现,否则使用静态方法更容易......

JDK 本身、apache commons 或许多框架都包含静态方法:

  • 字符串实用程序
  • Pattern.matches(正则表达式,输入)

----------

其实我猜你想知道像 JPA.java 这样的类是什么: https ://github.com/playframework/play/blob/master/framework/src/play/db/jpa/JPA.java

他们只使用静态方法并保持静态。这可能很奇怪,但实际上对我来说这有点像使用单例,除了这些方法是在静态上下文而不是对象上使用的。主要区别在于您不必每次都调用 getInstance()。

我认为这是为了可用性而设计的,因为调用“getInstance”对用户不友好,并且能够轻松地在任何地方获得会话(链接到线程)而不是在任何地方使用 xml 或 autowiring 注入 sessionFactory 是很酷的。 ..

您的教授可能会告诉您避免使用静态,因为如果您不正确使用它们可能会对您的设计造成危险。但是请注意,在许多情况下,用单例替换静态方法并不能使您的设计更好。即使您现在在实例方法上调用方法,对象仍将紧密耦合...

所以也许一个规则应该是避免使用静态,除非你真的不关心紧耦合。

  • 在这种情况下,当您调用 JPA.xxx() 方法时,您的代码与播放框架的 JPA 类紧密耦合。但我不认为 play 的设计目的是让您能够轻松地从一个框架切换到另一个框架,而无需至少进行一些返工......

  • 这与 EJB3 规范或类似的东西有很大的不同:如果 EJB3 实体管理器的方法是静态的,您将被迫通过调用 HibernateEntityManager.xxx() 或 ToplinkEntityManager.xxx() 将代码与实现紧密耦合。在这种情况下,有一个通用接口(我们不能在接口上添加静态方法)。

----------

  • 该类不是用于其他框架的规范的一部分。
  • JPA 类只有一种实现:由 play 完成的实现。他们可能不打算制作第二个。
  • 因此,当您使用 Play 框架时,与这个 Play 类的紧密耦合对我来说似乎没问题。
于 2011-05-25T13:33:58.980 回答
1

Play 采用函数式方法,例如node.js,并且可以说在 Scala 中比在 Java 中“更有意义”,例如Typesafe Stack正在推动的。正如其他海报所指出的,Java 正在使用字节码工具(a la Aspect J)进行增强,以更加无状态/功能化的方式运行;Scala 默认执行此操作。

于 2012-05-17T10:33:12.663 回答
0

您现在可以在 Play 中使用 Spring DI,请参阅https://stackoverflow.com/a/16552598/10433。我正在使用它,到目前为止它运行良好。

于 2013-10-04T05:30:22.180 回答
0

如果您是面向对象编程的纯粹主义者,则不应使用static方法/字段,但是可以安全地使用它们,并且不必担心恕我直言。

于 2011-03-04T11:11:03.633 回答
0

使用静态方法的原因之一是静态导入,它允许您缩短符号并使代码更具可读性。在使用像 Guava 或 Apache Commons 这样的实用程序库时尤其如此,您可能在其中有很多静态调用。

Play 2.1 现在通过使用控制器注入支持非静态控制器方法,因此尚不清楚为什么它们从一开始就不存在。

于 2013-09-20T10:20:17.250 回答