Play! 框架使用了大量的静态数据

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

我们(7个人和我)计划使用的发挥!一个涉及网络应用程序的项目框架。我们决定用 Play 来做!因为它看起来很有趣,我们都已经知道 Java,而且这个任务很难,所以我们想专注于实际的任务,而不是学习如何用不同的语言编程。

然而,我们总是被告知 永远不会在我们开发的任何 Java 程序中使用‘ static’,但是当我看到 Play 时!大约一半的方法是静态的。

我想,至少我们可以使用单例对象(例如 ^ ^)来编写我们的项目,但是我非常关心框架本身到底有多少静态对象。

那么,我应该担心这个吗?表演的方式!开发人员编写程序使得所有这些静态不会造成问题?

(例如,这根线对于为什么应该不惜一切代价避免静态成员有一番咆哮。)

15254 次浏览

如果你是一个面向对象编程的纯粹主义者,你不应该使用 static方法/字段,但是他们可以安全地使用,不必成为一个关注的原因。

从一个非常简短的观察,我会说它有点意义: web 请求是无状态的,所以 没有对象来接收请求(= 方法)。因此,在应用程序类上将 URI (例如“/article/archive? date = 08/01/08 & page = 2”)映射到名为 archive()的静态方法是有意义的。

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

在 Java 中使用单例与使用所有静态单例没有太大区别。国家也没有太多可以储存的东西。我觉得你不用担心。

那么,我应该担心这个吗?表演的方式!开发人员编写程序使得所有这些静态不会造成问题?

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

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

免责声明: 我对“玩”知之甚少

与编程中的任何问题一样,永远不会从来都不是正确答案。就像 一直都是。总有例外,正确的答案总是“视情况而定”。

的确,在纯 OO (我完全支持)中,静态的空间很小。但有时候它们也是有意义的。

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

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

另一件事是内部课程。如果不需要与包含类型的关系,通常需要使它们成为静态的。

我从来没有见过 开始!,但如果你说它超过50% 是静态的,那么我猜它可能是糟糕的设计。这也不例外; 许多框架都是如此。别因此而沮丧。绝对不要从中吸取教训!
但如果有用的话,你还是可以用的。

Play 只在有意义的情况下使用静态方法:

  • 在控制器层,因为控制器不是面向对象的。控制器充当 HTTP 世界(无状态,基于请求/响应)和完全面向对象的 Model 层之间的映射器。
  • 在工厂方法的模型层中,如 findAll ()、 count ()、 create () ,这些方法当然不依赖于任何特定的实例
  • 在一些提供纯实用函数的 play.libs. * 类中

运动中的静力学方法主要用于控制器的动作方法。这些方法只是为了从模型中获取必要的数据并将其公开给视图。

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

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

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

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

我也惊讶于静态方法的数量,但为什么不如果它工作良好..。

其实我不同意你老师的意见。

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

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

  • StringUtils
  • Match (regex,input)

----------

实际上,我猜你想知道类似 JPA.java 这样的类是什么样的: Https://github.com/playframework/play/blob/master/framework/src/play/db/jpa/jpa.java

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

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

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

因此,除非您并不真正关心紧密耦合,否则可能应该避免使用静态。

  • 在这种情况下,当您调用 JPA.xxx ()方法时,您的代码与框架的 JPA 类紧密耦合。但我不认为 Play 的设计是为了让你能够轻松地从一个框架切换到另一个框架,而不至少做一些修改... ..。

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

----------

  • 该类不属于 其他用途的规范 架构。
  • JPA 类只有 一个实现: 由 玩。他们可能不是 计划再做一个。
  • 因此 紧密耦合到这个 Play 类, 在使用 Play 框架时, 对我来说没问题。

游戏框架并不能很好地说明什么时候使用静力学是合适的,也不能证明你的老师是错误的。Play 是一种欺骗,解决了 Java 语言之外的静态问题。

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

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

Play 采用函数式方法,例如 Node Js,可以说在 Scala 中比在 Java 中“更有意义”,因为 类型安全堆栈正在推动这一点。正如其他发布者指出的那样,Java 正在使用字节码插装(如 AspectJ)进行扩展,以便以一种更无状态/函数化的方式运行; Scala 默认做到了这一点。

静态控制器方法当然是一个与播放关注的领域!框架,并在做了一些测试后,这是我没有做播放的主要原因!在项目中。你可以实际上看到这在自由和开放源码软件项目的地方播放!被使用。几乎没有控制器测试。原因是,对于静态方法,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!在爪哇世界。见鬼,为什么不用原版,只用 JRuby 呢?

使用静态方法的原因之一是静态导入,它允许您缩短表示法并使代码更具可读性。在使用诸如 Guava 或 ApacheCommons 之类的实用程序库时,尤其如此,因为在这些实用程序库中可能存在大量静态调用。

通过使用控制器注入,非静态控制器方法现在是 Play2.1中的 支持,因此不太清楚为什么它们从一开始就不存在。

您现在可以在 Play 中使用 SpringDI,请参阅 https://stackoverflow.com/a/16552598/10433。我正在使用它,到目前为止它工作得很好。

剪辑 现在在 Play 2.4中,注射是自动完成的。因此,只要在 routes文件的控制器路径的开头添加@就可以解决这个问题:

GET     /                  @controllers.Application.index()

对于旧版本(2.1到2.3) ,您必须在 Global 类中覆盖 getControllerInstance,如 文件中所解释的那样。