Играть! Фреймворк использует <много> статики

Вааа, игра! Фреймворк имеет так много статических методов. Там, где я хожу в школу, нам никогда не говорили ни о каких статиках, а играйте! использует его, как будто нет завтра. Это как-то хорошо? Если так, то почему?

Мы (7 человек и я) планируем использовать Play! рамки для проекта с участием веб-приложения. Мы решили сделать это с Play! потому что это выглядит довольно забавно, все мы уже знаем Java, и назначение довольно сложное, поэтому мы хотели сосредоточиться на реальном назначении, а не учиться программировать на другом языке.

Нам всегда говорили, однако, НИКОГДА не использовать "static" в любой Java-программе, которую мы разработали, но когда я смотрю на Play! ... Ну... около половины методов являются статическими.

Я предполагаю, что, по крайней мере, мы могли бы использовать одноэлементные объекты (используя Scala, например, ^^) для программирования нашего проекта, но я весьма обеспокоен тем, сколько статики на самом деле содержится в самой платформе.

Итак, я должен быть обеспокоен этим? Сделал так, как играть! разработчики запрограммировали это сделать так, чтобы все эти статики не создавали проблем?

(Например, этот поток рассуждает о том, почему статическими членами следует избегать любой ценой.)

14 ответов

Решение

Play использует статические методы только тогда, когда это имеет смысл:

  • на уровне контроллера, потому что контроллеры не являются объектно-ориентированными. Контроллеры действуют как отображение между миром HTTP (который не имеет состояния и основан на запросах / ответах) и уровнем модели, который полностью объектно-ориентирован.
  • в уровне модели для фабричных методов, таких как findAll(), count(), create(), которые, конечно, не зависят от каких-либо конкретных экземпляров
  • в некоторых классах play.libs.*, которые предоставляют чисто служебные функции

Игровые рамки не являются хорошей демонстрацией того, когда использование статики уместно, и не доказывают, что ваш учитель ошибался. Игра является своего рода обманом, решает проблемы статики вне языка Java.

Основная проблема заключается в том, что вам нужно обрабатывать несколько HTTP-запросов параллельно, а статические поля являются "глобальными". Таким образом, вам понадобится один экземпляр для каждого потока (или, что еще лучше, один экземпляр для HTTP-запроса) для определенных вещей, но некоторые из этих вещей возвращаются статическими методами в Play. Это работает, потому что играть! использования ThreadLocal-s, и поэтому решает проблему статики вне языка Java. Но это еще не все. Некоторые говорят, что методы контроллера по праву статичны. Конечно, но в простой Java это было бы неудобно, так как тогда вы не можете получить доступ к специфичным для запроса данным без какого-либо префикса, например req. в req.sessionи тогда тебе еще надо получить req откуда-то, как в качестве параметра метода статического контроллера, что еще больше хлопот. Тем не менее, в Play вы можете просто написать прямо session и, как, они просто статические поля. Это потому, что Play использует инструментарий байт-кода, чтобы изменить все эти ссылки на статические поля на что-то более умное. Опять же, решение за пределами языка Java. Это не статические поля в конце.

Так что, в общем, избегайте не финальной статики. Игра делает магию для вас, так что не бойтесь их в этом случае.

Из очень краткого обзора я бы сказал, что это имеет смысл: веб-запросы не сохраняют состояние, поэтому нет объекта для получения запроса (= метод). Таким образом, отображение URI, такого как "/article /archive? Date=08/01/08&page=2", в статический метод с именем archive() Я полагаю, ваш класс приложений имеет смысл.

РЕДАКТИРОВАТЬ Теперь в Play 2.4, инъекция выполняется автоматически. Так что просто добавив @ в начале пути контроллера в файле routes сделаю трюк:

GET     /                  @controllers.Application.index()

Для более старых версий (от 2.1 до 2.3) вам придется переопределить getControllerInstance в классе Global, как описано в Documentantion.

Как и в любом другом программировании, никогда не бывает правильного ответа. Как всегда Всегда есть исключения, и правильный ответ всегда "это зависит".

Это правда, что в чистой ОО (за которую я все) очень мало места для статики. Но это также правда, что иногда они просто имеют смысл.

Классический пример - служебные методы. Конечно, было бы лучше, если бы мы могли просто добавить наш abs() метод целочисленный. Но мы не можем; так что мы застряли с Math.abs(int i),

Я склонен думать, что правильно делать метод статичным, когда он не имеет ничего общего с самим экземпляром. Например, в классе Person, у вас может быть метод, который принимает список людей и возвращает количество людей, у которых сегодня день рождения. Возможно, вы можете сделать это только в самом классе, если данные, необходимые для выполнения вычислений, являются частными (что-то, что понимает пурист OO;)), но метод явно не имеет отношения к одному экземпляру Person.

Другое дело, внутренние классы. Вы часто хотите сделать их статическими, если вам не нужна связь с содержащим типом.

Я никогда не видел Play! но если вы скажете, что более 50% из них являются статичными, то я предполагаю, что они, вероятно, были плохо спроектированы. Это не исключение; много фреймворков есть. Не позволяй этому сбить тебя с толку. Определенно не учитесь на этом!
Но если это работает, вы все равно можете использовать его.

Основная проблема заключается в том, что статические методы имеют доступ только к другим статическим методам и полям, что приводит к "статическому прилипанию", в результате чего статические методы должны сближаться с остальной частью приложения (которая содержит его соавторов) через общие статические поля., что приводит к негибкости.

Отказ от ответственности: я не знаю много о "играть!"

Методы статического контроллера, безусловно, являются предметом озабоченности Play! Framework, и после некоторого тестирования, это главная причина для меня не делать 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 в контроллер. Дело в том, что в ваших тестах вы можете создать экземпляр IService непосредственно перед запуском контроллера, а затем протестировать результат на основе только что созданного IService.

В игре это становится очень сложно. Таким образом, тестирование модуля контроллера становится сложным. Для меня это серьезная проблема. Поэтому я склонен искать другие фреймворки, кроме Play! в мире Java. Черт возьми, почему бы не пойти с оригиналом и просто использовать JRuby?

Статический метод в игре в основном используется в методах действия контроллеров. Эти методы предназначены только для извлечения необходимых данных из модели и представления их для просмотра.

Они как-то соответствуют каждому возможному http-запросу и точно так же, как эти http-запросы полностью не сохраняют состояние.

В структурном программировании у вас есть процедуры, с одной стороны, и переменные, с другой, но в парадигме ООП вы рассматриваете процедуры и переменные в целом.

То есть у вас есть и объект с методами экземпляра (процедуры) и переменные экземпляра.

Но действия контроллера не сохраняют состояния, то есть они получают все переменные из запроса (возможно, также из кеша, но в этом случае вам нужен какой-то идентификатор сеанса, который в итоге приходит из запроса). Таким образом, действия контроллера аналогичны процедурам stateles, и поэтому они не вписываются в парадигму ООП, как модели.

Я полагаю, по крайней мере, мы могли бы использовать одноэлементные объекты

Синглтон в Java не имеет большого значения, чем использование всех статических. Там не так много, чтобы хранить, как государство, а также. Я думаю, что вы не должны беспокоиться об этом.

Итак, я должен быть обеспокоен этим? Сделал так, как играть! разработчики запрограммировали это сделать так, чтобы все эти статики не создавали проблем?

Это не будет. На самом деле все в порядке.

Я также удивлен количеством статических методов в игре, но почему бы и нет, если они работают нормально...

На самом деле я не согласен с вашим учителем.

Если объект не имеет состояния (то есть глобальных переменных), а содержит только методы для примера, это не дает вам никаких преимуществ в использовании объекта, а не статических методов. За исключением случаев, когда вы планируете добавить состояние позже (состояние, которое не должно быть общим), или если вы используете интерфейс и хотите иметь возможность легко переключать реализацию, проще использовать статические методы...

Сам JDK, Apache Commons или многие фреймворки включают статические методы:

  • StringUtils
  • Pattern.matches (регулярное выражение, вход)

----------

На самом деле, я думаю, вам интересно, что насчет классов, таких как JPA.java: https://github.com/playframework/play/blob/master/framework/src/play/db/jpa/JPA.java

Они используют только статические методы и сохраняют статическое состояние. Это может быть странно, но на самом деле для меня это немного похоже на использование синглтона, за исключением того, что методы используются в статическом контексте вместо объекта. Основное отличие состоит в том, что вам не нужно каждый раз вызывать getInstance().

Я думаю, что это было разработано так для удобства использования, потому что вызывать "getInstance" неудобно для пользователя, и было бы здорово иметь возможность легко получать сеанс везде (связанный с потоком) вместо того, чтобы внедрить sessionFactory везде с xml или автопроводкой...

Ваш профессор, возможно, советует вам избегать использования статики, потому что это может быть опасно для вашего дизайна, если вы не используете их правильно. Но обратите внимание, что во многих случаях замена статических методов на одноэлементный не улучшает ваш дизайн. Даже если вы теперь вызываете методы для метода экземпляра, объекты все равно будут тесно связаны...

Поэтому, возможно, следует придерживаться правила избегать использования статики, за исключением случаев, когда вас не интересует жесткая связь.

  • В этом случае, когда вы вызываете методы JPA.xxx(), ваш код тесно связан с классом JPA игровой среды. Но я не думаю, что игра разработана так, чтобы вы могли легко переключаться с одного фреймворка на другой без каких-либо переделок...

  • Это большая разница со спецификацией EJB3 или чем-то подобным: если методы менеджера сущностей EJB3 статичны, вы будете вынуждены тесно связать свой код с реализацией, вызывая HibernateEntityManager.xxx() или ToplinkEntityManager.xxx(). В этом случае существует общий интерфейс (и мы не можем добавлять статические методы на интерфейсы).

----------

  • Этот класс не является частью спецификации, используемой в других платформах.
  • Класс JPA имеет только одну реализацию: ту, которую выполняет play. И они, вероятно, не планируют делать второй.
  • Таким образом, тесная связь с этим классом Play, в то время как вы используете Play framework, кажется мне подходящей.

Play использует функциональный подход, например, node.js, и, возможно, имеет больше смысла в Scala, чем в Java, как, например, в стеке Typesafe. Как отмечали другие авторы, Java расширяется с помощью инструментария байт-кода (в аспекте J), чтобы вести себя более не зависящим от состояния / функциональным образом; Scala делает это по умолчанию.

Одной из причин использования статических методов является статический импорт, который позволяет сократить нотацию и сделать код более читабельным. Это особенно верно при использовании служебных библиотек, таких как Guava или Apache Commons, в которых может быть много статических вызовов.

Нестатические методы контроллера теперь поддерживаются в Play 2.1 с помощью инжекции контроллера, поэтому не очень понятно, почему их не было с самого начала.

Если вы являетесь специалистом по объектно-ориентированному программированию, вам не следует использовать static методы / поля, однако они могут использоваться безопасно, и не должны быть причиной для беспокойства ИМХО.

Теперь вы можете использовать Spring DI в Play, см. /questions/637323/integratsiya-play-framework-20-i-spring-framework/637343#637343. Я использую это, и это прекрасно работает до сих пор.

Другие вопросы по тегам