JavaFX: овчинка стоит выделки

10 июнь, 2009 - 12:59Виктор Вейтман

Сменить платформу проще всего тому, у кого нет с собой багажа. Значительно труднее сделать это, будучи обремененным грузом собственных разработок, ведь наверняка возникнет необходимость адаптации существующих программ. С другой стороны, тот, кто отвергает все новое, неизбежно пополняет ряды аутсайдеров. Поэтому, сталкиваясь с очередной технологией, следует задуматься, так ли серьезны преимущества ее использования? Оправдаются ли затраты на их освоение? Именно эти вопросы встают перед Java-разработчиком, впервые встретившимся с JavaFX.

Что подумает разработчик при первом знакомстве с JavaFX? Сразу же зачислит себя в ряды ее убежденных сторонников? Не факт, особенно если он уже имеет немалый опыт программирования на Java. Не исключено даже, что поначалу его охватит недоумение. Зачем облекать давно известные средства в новую оболочку? Чем скриптовый язык лучше собственно Java? Однако первое впечатление часто бывает обманчивым...

Аналогии не всегда уместны

Приступая к изучению нового языка программирования, специалист, имеющий хотя бы небольшой опыт практической работы, обычно пытается найти сходство с одним из известных ему языков и в дальнейшем сосредоточиться на различиях. Так, освоить Java легче тому, кто знает C++, а изучающий Perl наверняка обнаружит много общего с языком оболочки UNIX или Python. А на что же похож JavaFX Script – основа платформы JavaFX? Тут мнения могут разделиться.

Если судить по простейшим реализациям GUI, то JavaFX вполне может показаться экзотическим способом оформления обычного Java-кода декларативным языком. Так, в книге Джеймса Вивера (James L. Weaver) JavaFX Script Dynamic Java Scripting for Rich Internet/Client-Side Applications одним из первых приведен следующий пример:

Frame {
title: «Hello World-style example for JavaFX Script»
height: 100
width: 400
...
visible: true
}

Глядя на него, сразу же возникают ассоциации с классом Frame из пакета java.awt. Правда, там отсутствуют переменные height и width, но они легко обнаруживаются в суперклассе Component.

Другое учебное пособие, многократно представленное в Глобальной Сети, предлагает простейший математический пример, где четко просматриваются аллюзии на JavaScript:

def firstNumber = 2;
def secondNumber = 3;
var sum = firstNumber + secondNumber;
println(sum);

А обработка параметров командной строки демонстрирует сходство с языком С: в JavaFX также есть функция, которой сразу же после запуска программы передается управление, только называется она не main(), a run(), хотя способ описания функций, их параметров и возвращаемых значений больше напоминает Pascal.

Но, конечно, не стоит делать поспешных выводов. Скажем, присутствие распространенных имен Frame, height, width само по себе мало о чем говорит, тем более что с недавнего времени и класс Frame, и содержащий его пакет javafx.ui упразднены. С переменными, правда, ситуация сложнее, чем может показаться поначалу: в JavaFX Script тип переменной определяется либо по явному указанию при ее объявлении, либо по типу первых присваиваемых ей данных.

Однако по мере изучения JavaFX Script все четче просматривается сходство с Java. Так же, как и в Java, в нем используются пакеты и классы, операторы и выражения тоже по большей части совпадают. Результатом компиляции простейшей JavaFX-программы будет файл с расширением .class. И это уже, конечно, не случайно: JavaFX Script действительно основан на Java. И хотя он предоставляет собственные компилятор, интерпретатор и библиотеки, доступ к любому классу Java гарантирован. Это уже несомненное преимущество JavaFX, так как позволяет Java-разработчикам применять свой опыт в новой сфере – при создании RIA, «богатых», или развитых, интернет-приложений.

«Волшебный» сценарий dtfx.js

JavaFX овчинка стоит выделки
В NetBeans наиболее полно предоставлены средства для работы над JavaFX-проектом

RIA – сравнительно новое направление в веб-программировании. Такие приложения отличаются от обычных веб-программ тем, что, выполняясь в браузере, предоставляют интерфейс, характерный скорее для настольного ПО, и не гнушаются достаточно сложной обработкой данных на стороне клиента. Первые упоминания о «богатых» интернет-приложениях появились в литературе лишь несколько лет назад, но за это довольно короткое время стало ясно, что существующие средства разработки плохо вписываются в новую область. Язык JavaScript – одна из составных частей технологии Ajax – хорошо подходит для создания относительно простых программ, но мало пригоден в случае совместной работы нескольких программистов над сравнительно сложным приложением. Казалось бы, такой объектный язык, как Java, свободен от этого недостатка, но, с другой точки зрения, и он оказывается не идеальным решением. Даже если на минутку предположить, что кто-то реализовал в нем инструменты для непосредственного взаимодействия с элементами веб-страницы (подобно тому как это сделано в JavaScript), простые программы писать на этом языке будет неудобно – усилия по оформлению кода в виде класса станут соизмеримыми с трудозатратами по созданию самого кода.

Ситуационное сочетание JavaScript и Java также не является выходом. Программы имеют тенденцию развиваться, причем не всегда в предсказуемом направлении. Не исключено, что простой сценарий, выполняющий элементарные действия в составе веб-страницы, вырастет в сложный программный код, который в отсутствие поддержки объектов, имеет все основания стать совершенно неуправляемым. Именно поэтому JavaFX Script выглядит весьма удачным решением: на нем можно за очень короткое время написать простую программу, а при необходимости впоследствии использовать пакеты и классы.

Но каков бы ни был язык, применять его для создания не то что «богатых», но и обычных веб-приложений можно только при наличии средств, позволяющих запускать программу на клиентской машине. В случае JavaFX такие средства почти очевидны, и одно из них – механизм апплетов.

Для доставки сценария клиенту в качестве апплета компания Sun Microsystems предоставляет файл dtfx.js. В нем содержится JavaScript-код, который выполняет следующие задачи:

  • проверяет версию Java, установленную на клиентской машине (для JavaFX требуется JRE 6 Update 10 или старше);
  • создает дескриптор <applet> для включения в состав документа программы из указанного архива. Этот дескриптор, сгенерированный сценарием из dtfx.js, можно увидеть с помощью отладчика, например, при работе с Firefox для этой цели подойдет Firebug;
  • загружает библиотеки, необходимые для работы программы. Их объем достаточно велик, но в дальнейшем они будут подгружаться из кэша.

После загрузки JavaFX-программы dtfx.js сохраняет контроль над ней и позволяет обращаться к ее переменным и функциям. В принципе, средства взаимодействия между java-апплетом и JavaScript-кодом известны давно, но dtfx.js существенно упрощает этот процесс.

Говоря о запуске JavaFX-программы на стороне клиента, нельзя не упомянуть еще один способ – Java Web Start. В этом случае код, написанный на языке JavaFX Script, доставляется на клиентскую машину и запускается на ней точно так же, как и любая другая Java-программа.

Таким образом, становится ясно, зачем нужна поддержка кода, по структуре напоминающего JavaScript-сценарий, и чем хороша возможность декларативного описания фрагментов приложения. Но для того чтобы окончательно решить, стоит ли применять технологию JavaFX для написания сложных клиентских программ, желательно рассмотреть некоторые особенности языка JavaFX Script.

Непонятное ослабление правил

Как и любой другой объектно-ориентированный язык, JavaFX Script позволяет разработчику объявлять классы. В определении класса перечисляются переменные экземпляра и методы; этим JavaFX Script принципиально не отличается от Java или С++. Непривычными кажутся лишь способ указания типов переменных и ключевое слово function, с которого начинается заголовок метода, однако планировать использование языка невозможно, не приняв его синтаксис.

Особенности проявляются тогда, когда дело доходит до инициализации объекта. Если в Java для этой цели вызывается конструктор, то в JavaFX экземпляр класса декларируется с помощью литерала объекта. Например, если в программе определен класс MyObject, содержащий две целочисленные переменные экземпляра myVar1 и myVar2, то выражение, создающее экземпляр MyObject, инициализирующее имеющиеся в нем переменные и присваивающее ссылку на этот объект переменной myInstance, будет иметь следующий вид:

myInstance = MyObject {
myVar1: 10
myVar2: 20
};

Глядя на такой необычный способ создания экземпляра класса, возникает вопрос: действительно ли JavaFX является полноценным объектно-ориентированным языком? Поддерживаются ли в нем инкапсуляция, наследование и полиморфизм?

С наследованием и полиморфизмом дела обстоят совсем неплохо. Класс можно объявить подклассом, при этом он унаследует переменные и методы своего суперкласса. При необходимости метод можно переопределить с помощью ключевого слова override (подобная особенность синтаксиса только приветствуется, благодаря ей исходный код программы становится более удобочитаемым). Хорошо работает и перегрузка методов. При попытке объявить два метода с одним именем, но разным набором параметров, конфликтов не возникает.

Но если к наследованию и полиморфизму, реализованным в JavaFX, претензий нет, то инкапсуляция поддерживается, мягко говоря, не полностью. Не существует средств, которые могли бы запретить обратиться из текущего программного модуля к переменным экземпляра, содержащимся внутри объекта. Несмотря на то что в JavaFX поддерживается шесть модификаторов доступа, ключевого слова private среди них нет. Можно ограничить область видимости переменной или метода пакетом, модулем, дочерними классами, можно даже предоставить доступ только для чтения или только для инициализации. Единственное, чего нельзя сделать – полностью запретить обращаться к переменной или методу из-за пределов класса. Чем руководствовались разработчики, убирая модификатор private (ведь в ранних версиях JavaFX он присутствовал), неясно. Можно лишь придумывать организационные меры, ограничивающие доступ к содержимому объектов. Так, в масштабном проекте имеет смысл потребовать, чтобы определение каждого класса содержалось в отдельном программном модуле, тогда предоставляемый по умолчанию доступ автоматически превратит переменные и методы классов в закрытые.

Но как бы то ни было, отсутствие инкапсуляции в полном объеме – неприятный сюрприз. Как показывает опыт, если разработчику, не имеющему достаточного опыта, предоставляется хоть малейшая возможность обратиться к переменной экземпляра напрямую, минуя методы доступа, это будет сделано. Конечно, у создателей JavaFX наверняка имелись какие-то аргументы, но от этого не легче. Вести проект так, чтобы он ни на минуту не выходил из под контроля, – трудная задача, и каждое отступление от принципов ООП еще больше усложняет ее.

Такого еще не бывало

JavaFX овчинка стоит выделки
Специализированный редактор JavaFXPad позволяет быстро проверить работоспособность небольшого фрагмента кода

Есть в стандартной библиотеке Java класс PropertyChangeEvent. С ним знаком любой разработчик, имеющий хотя бы небольшой опыт программирования на данном языке. Как и следует из названия класса, событие, описываемое им, генерируется при изменении текущего значения свойства. И если программисту необходимо отслеживать такие факты, он должен написать обработчик и связать его с источником, вызвав метод addPropertyChangeListener() последнего. Но что делать, если ни в классе, которому принадлежит свойство, ни в его суперклассах этот метод не предусмотрен? Тогда следует самостоятельно реализовать addPropertyChangeListener() или его аналог, позаботиться об отслеживании изменения свойства и генерации события, одним словом, выполнить дополнительную рутинную работу, естественно, отвлекающую от главной цели. А вспомнился PropertyChangeEvent постольку, поскольку его можно условно считать аналогом триггеров замены JavaFX Script, кроме того, он, пусть отдаленно, напоминает связывание, реализованное в этом языке.

При создании JavaFX были приняты меры для того, чтобы в процессе написания программ разработчик мог сосредоточиться на основных задачах, и, соответственно, реализованы средства, упрощающие выполнение некоторых (пусть немногих) задач, возникающих при создании приложений. Одним из них является механизм триггеров замены. С помощью ключевого слова on replace с переменной можно связать фрагмент кода, который будет выполнен, когда ее значение изменится. Немаловажен тот факт, что посредством триггеров замены можно контролировать любые переменные, что существенно расширяет их сферу применения по сравнению с упомянутым PropertyChangeEvent.

Однако разработчики JavaFX не остановились на этом и реализовали принципиально новое средство, получившее название связывания (binding). Если в программе используются две переменные с именами, например x и y, то одну из них можно связать с другой, применяя ключевое слово bind:

var y bind x;

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

Значение этого средства трудно переоценить. Скажем, при реализации программы в рамках архитектуры модель-представление-контроллер (MVC) появляется возможность полностью разделить представление и контроллер. Путем связывания можно без труда добиться того, чтобы изменения модели сразу же отражались в представлении, а данные, введенные посредством представления, передавались модели.

Java Web Start

Так называется набор средств, которые позволяют загружать, инсталлировать и выполнять программы, размещенные в глобальной сети. Для того чтобы приложение могло быть запущено с помощью Java Web Start, его надо оформить в виде Jar-файла и выложить на сервер. Кроме того, там же должен находиться так называемый JNLP-файл, который представляет собой XML-документ, включающий следующие основные данные:

  • имя Jar-файла с кодом программы;
  • URL каталога, в котором находится Jar-файл;
  • номер версии JRE, необходимой для запуска программы.
  • информацию о том, что программа является Java-приложением, и имя класса, содержащего метод main().

По умолчанию программа запускается в «песочнице» и имеет те же права, что и обычный Java-апплет, но набор ее привилегий можно расширить, если снабдить электронной подписью.

Инструмент должен быть под рукой

Наличие инструментов – немаловажный фактор, влияющий на выбор разработчиком той или иной технологии. Язык программирования даже с самыми богатыми выразительными средствами вряд ли будет востребован, если для него нет удобной среды разработки. К счастью, с этой точки зрения JavaFX выглядит весьма пристойно.

«Классическим» инструментом для создания JavaFX-приложений считается NetBeans IDE. В версии 6.5 данного продукта предоставляются средства, необходимые для написания и отладки JavaFX-кода, а также для доставки программы на клиентское устройство. Для тех, кто предпочитает использовать Eclipse, предлагается специальный модуль расширения. Он дополняет список поддерживаемых типов проектов JavaFX-приложением и предоставляет стандартный набор возможностей для работы над ним. Если же программист принципиально не пользуется интегрированными средами разработки, он может применять компилятор javafxc.exe и интерпретатор javafx.exe, входящие в состав JavaFX SDK.

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

Кто победит в конкурентной борьбе

Ни для кого не секрет, что JavaFX – не единственный инструмент для создания RIA. Sun Microsystems несколько подзадержалась с его выпуском и сейчас вынуждена догонять не только фактического лидера данной области Adobe Flex, но и активно развивающуюся Microsoft Silverlight. Каковы же шансы JavaFX в этой конкурентной борьбе? Адекватно сравнить три данные технологии – чрезвычайно трудная задача, ведь необходимо принять во внимание множество факторов. Однако учитывая, что пока RIA только набирают популярность, можно предположить что большинство программистов, приступая к освоению новой области, предпочтут воспользоваться максимально привычным и знакомым инструментом. И в таком случае на стороне JavaFX окажется армия действующих Java- разработчиков, что даст ей неплохие шансы на успех. Но, так или иначе, приятно отметить тот факт, что для создания «богатых» приложений уже существует богатый выбор средств.