3. Разметка Groovy
Объем интересных особенностей Groovy превышает ранее перечисленные, к ним так же можно отнести автономные приложения, диспетчеризацию динамического метода, параметры метода по умолчанию (как в setBoardSize из Листинга 2) и синтаксис формулы маршрута. Несмотря на это, полезность Groovy будет оцениваться не количеством своих свойств, а объемом сэкономленного времени.
Преимуществом этого языка является возможность вызова объектов Java и их легкого внедрения в программы Java. Однако при рассмотрении версии 1.0 бета 4 неясно, возможно ли с помощью сценария Groovy создать программу быстрее, чем с Java. Мне понадобилось много времени, чтобы перенести Листинг 1 в Листинг 2 не только по причине наличия противоречий в текущей реализации, но и по причине наличия не внедренных свойств.Обычно, когда я берусь за работу с новым языком сценариев, перенос короткой программы из другого языка занимает короткий промежуток времени. Обратите внимание на то, что в примере из Листинга 2 делается полностью уточненная ссылка на java.awt.Graphics и java.awt.event.ItemEvent.SELECTED, несмотря на импорт пакетов java.awt и java.awt.event и необусловленную ссылку на другие классы Java, такие как Dimension и BorderLayout. Сценарий Groovy не сможет работать без полностью определенных параметров, что возможно является неполадкой, которую в будущем следует устранить. Кроме того, обнаружилось, что ни оператор модуля, ни такие бинарные операторы, как and, or и xor не были введены в действие.
Единственное свойство, которое мне бы хотелось протестировать, - это расширяемое свойство разметки Groovy. Обратите внимание на то, что компоненты Swing реализованы с помощью класса SwingBuilder и уникального иерархического синтаксиса (см. Листинг 2). Этот синтаксис не является собственным синтаксисом Groovy, он реализован посредством класса SwingBuilder. Компоновщики HTML и XML тоже были внедрены. Здесь не будет описываться, как именно они работают. Разметчик Groovy позволяет выразить более точно отношения на базе древовидных элементов.
Обратите внимание на различия между компоновкой Swing-компонентов в Листинге 1 и Листинге 2. Не так ли, с помощью Groovy все выглядит значительно проще? Но внешность может быть обманчива. Разметка усложняет процесс внедрения слушателей, которые управляют отдельными объектами, такими как boardContainer и board (см. Листинг 1). Придется вставить клудж для слушателя в Листинге 2, чтобы использовать знания структуры скомпонованного фрейма для получения доступа к панели прокрутки. Конечно, лучше избегать сценариев подобных представленному в Листинге 1, но тогда какой смысл в Groovy?
Языки написания сценариев могут многое предложить Java, Groovy подает надежды. JSR будет представлен в качестве проекта с открытым исходным кодом, поэтому Groovy будет нацелен на соответствие требованиям пользователей. О Groovy можно узнать больше, посетив Web-сайт проекта и JSR 241 (см. «Дополнительные ресурсы»).
4. Дополнительные ресурсы
- http://groovy.codehaus.org/ - специализированный Groovy ресурс
- http://developer.sun.com/ - Ресурс Sun для Java разработчиков. Зарегистрированные пользователи смогут посмотреть Bug Id 4919127 (http://developer.java.sun.com/developer/bugParade/bugs/4919127.html) Bug Id 4960791 (http://developer.java.sun.com/developer/bugParade/bugs/4960791.html) в Java Bug Parade
- http://service.bfast.com/bfast/click?bfmid=43945&sourceid=0039879758&bfpid=0131422464&bfmtype=Book - Java Community Process Java Specification Requests "JSR 241: The Groovy Programming Language"
Статью Даниеэля Саварез (Daniel Savarese) подготовила Ерофеева Вера
Листинг 1. Java – «многословный» язык, что видно по компоновке компонентов Swing и слушателям событий в JavaCheckerboard,
package example;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JavaCheckerboard extends JPanel {
public static class BoardPanel extends JPanel {
int width, height, tileWidth, tileHeight;
int[] initX;
public BoardPanel(int width, int height,
int tileWidth, int tileHeight) {
initX = new int[2];
setBoardSize(width, height, tileWidth,
tileHeight);
}
public void setBoardSize(int width, int height,
int tileWidth, int
tileHeight)
{
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
initX[0] = 0;
initX[1] = tileWidth;
setBoardSize(width, height);
}
public void setBoardSize(int width, int height) {
Dimension size;
this.width = width*tileWidth;
this.height = height*tileHeight;
size = new Dimension(this.width, this.height);
setPreferredSize(size);
}
private void paintTiles(
Graphics g, int firstTile, Color color) {
int x, y = 0, dx = 2*tileWidth;
g.setColor(color);
while(y < height) {
x = initX[firstTile];
while(x < width) {
g.fillRect(x, y, tileWidth, tileHeight);
x+=dx;
}
y+=tileHeight;
firstTile ^= 1;
}
}
public void paint(Graphics g) {
paintTiles(g, 0, Color.WHITE);
paintTiles(g, 1, Color.BLACK);
}
}
BoardPanel board;
JScrollPane boardContainer;
public class SizeListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
if(e.getStateChange() == ItemEvent.SELECTED) {
String item = (String)e.getItem();
JViewport viewport;
int size;
if("2x2".equals(item))
size = 2;
else if("4x4".equals(item))
size = 4;
else if("8x8".equals(item))
size = 8;
else
size = 16;
board.setBoardSize(size, size);
viewport = boardContainer.getViewport();
viewport.setViewPosition(new Point(0, 0));
repaint();
}
}
}
public JavaCheckerboard() {
JComboBox boardSize;
board = new BoardPanel(8, 8, 50, 50);
boardContainer = new JScrollPane();
boardContainer.setViewportView(board);
boardSize = new JComboBox();
boardSize.addItem("2x2");
boardSize.addItem("4x4");
boardSize.addItem("8x8");
boardSize.addItem("16x16");
boardSize.setSelectedIndex(2);
boardSize.addItemListener(new SizeListener());
setLayout(new BorderLayout());
add(boardContainer);
add(boardSize, BorderLayout.NORTH);
}
public static final void main(String[] args) {
JFrame frame = new JFrame("Fun and Games");
frame.getContentPane().add(
new JavaCheckerboard());
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
Листинг 2. Groovy менее многословен, чем Java, но его слабая типизация и мириады свойств могут заманить в ловушку.
package example
import java.awt.*
import javax.swing.*
import javax.swing.event.*
import groovy.swing.*
class BoardPanel extends javax.swing.JPanel {
private Integer width
private Integer height
private Integer tileWidth
private Integer tileHeight
public setBoardSize(Integer width, Integer height,
Integer tileWidth =
this.tileWidth,
Integer tileHeight =
this.tileHeight)
{
this.width = width*tileWidth
this.height = height*tileHeight
this.tileWidth = tileWidth
this.tileHeight = tileHeight
setPreferredSize(new Dimension(
this.width, this.height))
}
public void paint(java.awt.Graphics g) {
dx = 2*tileWidth
checkerboard = { isOffset, color |
y = 0
g.setColor(color)
while(y < height) {
x = (isOffset ? tileWidth : 0)
while(x < width) {
g.fillRect(x, y, tileWidth, tileHeight)
x+=dx
}
y+=tileHeight
isOffset = !isOffset
}
}
checkerboard(false, Color.WHITE)
checkerboard(true, Color.BLACK)
}
}
swing = new SwingBuilder()
board = new BoardPanel(boardSize:[8,8,50,50])
JFrame frame = null
listener = { event |
if(event.stateChange ==
java.awt.event.ItemEvent.SELECTED) {
switch(event.item) {
case "2x2": size = 2; break
case "4x4": size = 4; break
case "8x8": size = 8; break
default : size = 16
}
board.setBoardSize(size, size)
if(frame != null) {
scroll =
frame.contentPane.components[0].components[1]
scroll.viewport.viewPosition = new Point(0, 0)
frame.contentPane.repaint()
}
}
}
frame = swing.frame(title:"Fun and Games",
size:[400,400],
defaultCloseOperation:JFrame.
EXIT_ON_CLOSE) {
panel(layout:new BorderLayout()) {
comboBox(items:["2x2", "4x4", "8x8", "16x16"],
selectedIndex:2,
constraints:BorderLayout.NORTH,
itemStateChanged:listener)
scrollPane(viewportView:board,
constraints:BorderLayout.CENTER)
}
}
frame.visible = true