玩!框架使用静态的<lot>


75

Waaah,戏剧!框架有很多静态方法。我在哪里上学,我们被告知从来没有使用任何静态的,但玩!像没有明天一样使用它。可以吗?如果是这样,为什么?

我们(和我7个人)正计划使用Play!涉及Web应用程序的项目的框架。我们决定通过Play做到这一点!因为这样做看起来很有趣,所以我们所有人都已经知道Java,并且分配工作非常困难,因此我们希望专注于实际分配,而不是学习如何使用其他语言进行编程。

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

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

那么,我应该对此予以关注吗?玩的方式!开发人员对其进行了编程,以使所有这些静态变量都不会造成问题?

(例如,该线程对为什么不惜一切代价避免使用静态成员的做法感到愤慨。)


3
呃...您可能应该问您的教授,或者其他人。此外,对于世界其他地区,自然也不会认同与您自己的编程习惯有关的好坏观念,因此请习惯一下。:)
放松

4
@表示虽然不鼓励使用静态变量,但是“从不使用静态变量”是一种夸大的说法
Suraj Chandran

21
<exaggeration>标签是不可见的。:)
Nishant

就是这样,我们的教授是面向对象的纯粹主义者。他总是向我们警告使用静电的危险,除非我们能提供一个合理的解释,说明为什么我们仍然使用它们并且不担心会产生后果,否则他会提醒我们使用静电。
Saew 2011年

@Nishant @jensgram我明白了,谢谢;)
Saew 2011年

Answers:


95

只有在合理的情况下,Play才会使用静态方法:

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

1
另外,主要问题是静态成员而不是静态方法。在游戏中,只有threadlocals作为静态成员。
niels

3
结合使用静态validation成员 (请参见示例)和ThreadLocalshow,表明静态并非在所有情况下都适用。
守护进程

9
我已经习惯了通过DI框架注入依赖项的控制器。您将如何使用静态对象实现DI?
ripper234 2011年

6
@Guillaume我不得不非常不同意您的意见,Play显示了编写Java的最糟糕的做法,而且static永远不会有在Java代码中使用s的借口。不变性不是由静态表示的,相反,静态表示共享状态,这与您声明的状态完全相反。然后是当然反射有趣的东西像调用错误的实例静态方法,因为静态方法,甚至没有配对,他们在定义的类。总之,static在Java中是一个巨大的代码味道,并在所有你应该不存在目的是编写现代Java。
Esko

2
@Esko我绝对同意您的观点,Play在scala中可能很有价值,但是在Java中它总结了一些不良做法。
Snicolas 2014年

34

Play框架不能很好地说明何时使用静态变量是适当的,也不能证明您的老师是错误的。Play有点作弊,解决了Java语言之外的静态问题。

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

因此,通常应避免使用非最终静态变量。Play可以为您带来魔力,因此在这种情况下请不要害怕。


15

从一个非常简单的介绍一下,我会说这样的有道理:web请求是无状态的,所以没有对象接收请求(=方法)。因此,将URI(例如“ / articles / archive?date = 08/01/08&page = 2”)映射到调用的静态方法archive()上,我想,您的应用程序类很有意义。


8

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

GET     /                  @controllers.Application.index()

对于较旧的版本(2.1到2.3),您必须重写Global类中的getControllerInstance,如Documentantion中所述。


5

与编程中的任何内容一样,从来没有永远不是正确的答案。像往常一样。总是有例外,正确的答案永远是“取决于”。

的确,在纯OO(我全力以赴)中,几乎没有静态空间。但是,有时候它们只是有意义,这也是事实。

经典示例是实用程序方法。当然,最好将abs()方法附加到Integer。但是我们不能;所以我们坚持下去Math.abs(int i)

我倾向于认为,与实例本身无关的方法使方法静态化是正确的。例如,在class中Person,您可以使用一个方法来获取人员列表,并返回今天有生日的人数。也许只有在进行计算所需的数据是私有的(OO纯粹主义者会理解的东西)的情况下,才可以在类本身中执行此操作,但是该方法仍然显然与单个Person实例无关。

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

我从未看过Play!但是,如果您说它的50%以上是静态的,那么我猜想它可能设计不好。也不例外。很多框架。不要让它让你失望。绝对不要从中学到东西!
但是,如果有效,您仍然可以使用它。


22
Play的设计不是很糟糕,但是它偏离了大多数Java库的设计方式。
Marcus Downing

4

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

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


4

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

通常,您有一个类似以下的构造函数:

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?


3

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

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

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

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

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


2

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

Java中的Singleton与使用所有静态方法没有太大区别。状态也存储不了多少。我认为您不必为此担心。

那么,我应该对此予以关注吗?玩的方式!开发人员对其进行了编程,以使所有这些静态变量都不会造成问题?

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


1
好吧..我猜。我的良心仍然对使用静态
变量感到na恼

1
-1,因为在具有非静态方法的单例中,我们可以应用继承和多态性,但是在静态世界中,我们不能使用OOP的这些好处。所以它几乎不一样。
ses

用静态语言代替对单例的良好语言支持可以说是Java语言中的最大缺陷。Scala的伴随对象系统是一个案例研究,说明这种微小的变化如何产生巨大的好处。即使您绝不会在现实世界中交换实现,但能够在测试中交换实现几乎总是有用的。除了少数例外,我非常同意教授的观点。单身人士并不难。
莎拉·G

1

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

其实我不同意你的老师。

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

JDK本身,Apache Commons或许多框架都包含静态方法:

  • StringUtils
  • Pattern.matches(正则表达式,输入)

----------

实际上我猜你想知道JPA.java之类的东西是什么:https : //github.com/playframework/play/blob/master/framework/src/play/db/jpa/JPA.java

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

我认为这是出于可用性的目的而设计的,因为调用“ getInstance”并不友好,并且能够轻松地在任何地方(链接到线程)获取会话,而不是在所有地方都使用xml或自动装配注入sessionFactory是很酷的。 ..

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

因此,也许一条规则应该是避免使用静态变量,除非您不太在乎紧密耦合。

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

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

----------

  • 该类不是其他框架上使用的规范的一部分。
  • JPA类只有一种实现:一种是通过游戏实现的。而且他们可能不打算再制造一个。
  • 因此,在您使用Play框架时,与此Play类紧密耦合对我来说似乎可以。

1

Play采用了一种功能性方法,例如,例如node.js,并且可以说,随着Typesafe Stack的推出,在Scala中比在Java中更有意义。正如其他发布者所指出的那样,正在使用字节码检测工具(方面J)对Java进行增强,使其表现出更无状态/功能的方式。Scala默认情况下会这样做。


0

如果您是面向对象编程的纯粹主义者,则不应使用static方法/字段,但是可以安全地使用它们,而不必成为引起恕我直言的原因。


2
我不确定。static在某些环境中,随意使用字段会导致讨厌的类加载器泄漏。
skaffman 2011年

1
见先前的评论:)根据我的教授,静令人关注的问题..
Saew

0

使用静态方法的原因之一是静态导入,它使您可以缩短表示法并使代码更具可读性。当使用实用程序库(例如Guava或Apache Commons)时,尤其如此,在这些实用程序库中,您可能会有很多静态调用。

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


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.