Play! framework uses a <lot> of statics

China☆狼群 提交于 2019-11-28 03:31:47

Play uses static methods only when it makes sense:

  • in the controller layer, because controllers are not object oriented. Controllers act as mapper between the HTTP world (that is stateless, and request/response based) and the Model layer that is fully object oriented.
  • in the model layer for factory methods, like findAll(), count(), create() which of course don't depend of any particular instances
  • in some play.libs.* classes that provides purely utility functions

Play framework is not a good demonstration of when using statics is appropriate, nor it proves that your teacher was wrong. Play is kind of cheating, solves the issues of statics outside the Java language.

The key problem is that you have to process multiple HTTP requests in parallel, and static fields are "global". So you will need one instance per thread (or even better, one instance per HTTP request) for certain things, yet some of those things are returned by static methods in Play. That works because Play! uses ThreadLocal-s heavily, and so it solves a problem of statics outside the Java language. But that's not everything. Some say that controller methods are rightfully static. Sure, but in plain Java it would be inconvenient, as then you can't access request-specific data without some kind of prefix, like req. in req.session, and then you still have to get req from somewhere, like as a parameter of the static controller method, which is even more hassle. Yet in Play you can you just directly write session and like, they are just static fields. That's because Play uses bytecode instrumentation to change all those static field references to something smarter. Again, a solution outside the Java language. Those are not static fields at the end.

So, in general, avoid non-final statics. Play does the magic for you though, so don't afraid of them in this case.

From a very brief look, I'd say it kind of makes sense: web requests are stateless, so there is no object to receive the request (=the method). Thus, mapping an URI such as "/articles/archive?date=08/01/08&page=2" to a static method called archive() on, I guess, your application class makes sense.

EDIT Now in Play 2.4, the injection is done automatically. So just adding @ at the beginning of the controller path in the file routes will make the trick:

GET     /                  @controllers.Application.index()

For older versions (2.1 to 2.3) you will have to override getControllerInstance in the Global class, like explained in the Documentantion.

As with anything in programming, never ever is never the right answer. Just like always. There are always exceptions and the right answer is always 'it depends'.

It's true that in pure OO (which I'm all for) there is very little room for statics. But it's also true that sometimes they just make sense.

The classic example is utility methods. Sure, it would be better if we could just append our abs() method to Integer. But we can't; so we're stuck with Math.abs(int i).

I tend to think it's just correct to make a method static when it has nothing to do with the instance itself. For instance, in a class Person, you could have a method that takes a list of people, and returns the number of people that have a birthday today. Maybe you can only do this in the class itself if the data needed to do the calculation is private (something an OO purist would understand ;)) but still the method clearly has no relation to a single Person instance.

Another thing is internal classes. You often want to make them static if you don't need the relation with the containing type.

I've never seen Play! but if you say that over 50% of it is static, then I'm guessing it was probably badly designed. That's no exception; a lot of frameworks are. Don't let it get you down. Definately don't learn from it!
But if it works you can still use it.

The main problem is that static methods only have access to other static methods and fields, which results in 'static cling' whereby the static methods have to rendezvous with the rest of the application (which contains its collaborators) via common static field(s), which leads to inflexibility.

Disclaimer: I don't know much about 'play!'

Static controller methods are certainly an area of concern with the Play! framework, and after having done some testing, it is the main reason for me not doing Play! in projects. You can actually see this where in FOSS projects where Play! is used. There is little or no Controller testing. The reason, with static methods, DI becomes difficult. This is where they should have spent even more time with ASP.NET MVC, from where Play! already takes a bit of inspiration.

Typically you have a constructor like this:

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

Then you use DI to inject the IService implementation into the Controller. The point being that in your tests, you can instantiate the IService just prior to running the Controller, and then test the result based on the IService you just produced.

In Play this becomes very hard. Thus Controller unit testing becomes hard. That is, to me, a significant problem. I would therefore tend to look for other frameworks than Play! in the Java world. Heck, why not go with the original and just use JRuby?

Statics method in play are mainly used in controllers action methods. These methods are meant to just fetch the necesary data from the model and expose it to views.

They correspond somehow to each possible http request, and, just like those http request are completely stateless.

On structural programming you have procedures on the one hand, and variables on the other, but on OOP paradigm you treat procedures and variables as a whole.

That is, you have and object with instance methods (procedures) and instance variables.

But controller actions are stateless, that is they get all there variables from the request (maybe also from the cache, but in that case you need some sort of session id that finally comes from the request). So controller actions are just like stateles procedures, and that's why they don't particularly fit in the OOP paradigm, as models do.

I suppose, at the very least, we could use singleton objects

Singleton in Java does not makes much difference than using all static. There is not much to store as state as well. I think you should not worry about it.

So, should I be concerned about this? Did the way the Play! developers programmed it make it so that all these statics don't pose a problem?

It would not. In fact, it's alright.

Im also surprised by the number of static methods in play, but why not if it works fine...

Actually i don't agree with your teacher.

If an object has no state (ie global variables) but just contains methods for exemple, it doesn't give you any benefits to use an object rather than static methods. Except if you are planning to add a state later (state that should not be shared), or if you are using an interface and want to be able to switch easily the implementation, it's easier to use static methods...

JDK itself, apache commons or many frameworks are including static methods:

  • StringUtils
  • Pattern.matches(regex,input)

----------

Actually i guess you wonder what's about classes like JPA.java: https://github.com/playframework/play/blob/master/framework/src/play/db/jpa/JPA.java

They use only static methods and keep a static state. This could be strange, but actually for me it's a bit like using a singleton except the methods are used on a static context instead of an object. The main difference is that you don't have to call getInstance() everytime.

I think this was designed like that for usability, because it is not user friendly to call "getInstance" and it's cool to be able to get easily a session everywhere (linked to the thread) instead of injecting the sessionFactory everywhere with xml or autowiring...

Your professor perhaps tells you to avoid using statics because it can be dangerous for your design if you don't use them right. But notice in many cases, replacing static methods by a singleton doesn't make your design better. Even if you now call the methods on an instance method, objects will still be tightly coupled...

So perhaps a rule should be to avoid using statics except when you don't really care about a tight coupling.

  • On this case, when you call JPA.xxx() methods, your code is tightly coupled to play framework's JPA class. But i don't think play is designed so that you would be able to easily switch from one framework to another without at least some rework...

  • It's a big difference with EJB3 spec or stuff like that: if the EJB3 entity manager's methods where static, you would be forced to tightly couple your code to the implementation by calling HibernateEntityManager.xxx() or ToplinkEntityManager.xxx(). In this case, there is a common interface (and we can't add static methods on interfaces).

----------

  • That class is not part of a specification used on other frameworks.
  • The JPA class has just one implementation: the one done by play. And they probably are not planning to make a second one.
  • Thus a tight coupling to this Play class, while you are using Play framework, seems ok for me.

Play takes a functional approach, like node.js for example, and arguably makes 'more sense' in Scala than in Java, as the Typesafe Stack is pushing, for example. As other posters have pointed out, Java is being augmented using bytecode instrumentation (a la Aspect J) to behave in a more stateless/functional way; Scala does this by default.

Peter Lawrey

If you are an Object Orientated Programming purist, you shouldn't use static methods/fields, however they can be used safely, and don't have to be a cause for concern IMHO.

One of the reasons to use static methods are the static imports which allow you to shorten the notation and make the code more readable. This is specially true when using utility libraries like Guava or Apache Commons in which you might have a lot of static calls.

Non-static controller methods are now supported in Play 2.1 via using controller injection, so it's not very clear why they were not there from start.

Andrew Swan

You can now use Spring DI within Play, see https://stackoverflow.com/a/16552598/10433. I'm using it and it works fine so far.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!