Статьи

Эксперименты с первоклассными методами (FCM)

У Стивена Колебурна есть прототип реализации предложения закрытия FCM . Мне потребовалось некоторое время, чтобы загрузить и поиграть с новым синтаксисом и функциональностью.

Я попытался сосредоточиться на некоторых функциональных возможностях, которые FCM предоставляет, а другие предложения о закрытии — нет.
А именно метод и полевые литералы. Я думаю, что FCM может помочь создать гибкие модели для компонентов качелей. В прошлом я делал это, используя простое отражение, но FCM облегчает задачу.


Это скриншот демонстрационного приложения.


Он отображает три списка и одну таблицу, все из которых поддерживаются одной и той же коллекцией компонентов SuperHero.

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

SwingUtilities.invokeLater(#startApp());

Это вызывает мой метод startApp () в потоке отправки событий. Я должен признать, что, хотя я не фанат встраивания, это было предпочтительнее, чем традиционный метод построения Runnable и передачи его invokeLater

Вот очень простая ListModel, которая может предоставить любое открытое поле объекта.

/**
* Wraps a list of elements and exposes one field to the list model
* interface
*
* @param <E>
*/
private class FCMFieldListModel<T> extends AbstractListModel {

private List<T> backingList;
private Field targetField;

public FCMFieldListModel(List<T> data, Field target) {
backingList = data;
targetField = target;
}

@Override
public Object getElementAt(int index) {
try {
return targetField.get(backingList.get(index));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}

В моем случае я создаю список супергероев и хочу выставить поле фамилии.

FCMFieldListModel<SuperHero> lastListModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#lastName);

Последний параметр — это новый буквенный синтаксис поля из FCM. Это позволяет мне безопасный способ указать, какое поле я хочу открыть.

Чтобы создать больше моделей списков, которые предоставляют другие поля, мне просто нужно создать еще одну FCMFieldListModel и предоставить другое поле.

FCMFieldListModel<SuperHero> listModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#firstName);

Теперь большую часть времени боб не будет выставлять поле. Вместо этого методы getter / setter используются для раскрытия этой информации. FCM имеет литералы методов, а также полевые литералы. Код для FCMMethodListModel очень похож на FCMFieldListModel, но он принимает ссылку на метод вместо ссылки на поле.

       /**
* Wraps a list of elements and exposes one method to the list model
* interface
*
* @param <E>
*/
private class FCMMethodListModel<E> extends AbstractListModel {

private List<E> backingList;
private Method targetMethod;

public FCMMethodListModel(List<E> data, Method target) {
backingList = data;
targetMethod = target;
}

@Override
public Object getElementAt(int index) {
try {
Object item = backingList.get(index);
return targetMethod.invoke(item);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}

По сути, это позволяет вам сообщить модели списка, какой метод вашего компонента должен вызываться для представления вашего компонента в списке. Он используется так же, как модель FCMFieldListModel.

FCMMethodListModel<SuperHero> fullListModel = new FCMMethodListModel<SuperHero>(heroes, SuperHero#getFullName());

Наконец, я использовал эту же технику для построения табличной модели.

FCMTableModel<SuperHero> superTableModel = new FCMTableModel<SuperHero>(heroes,
SuperHero#getFirstName(), SuperHero#getLastName(),
SuperHero#getHeroName(), SuperHero#getFirstAppearance());

Конструктор принимает список SuperHeroes и список переменных для использования в качестве столбцов. Этот код — все, что нужно для заполнения таблицы, видимой в центре скриншота.

Первый столбец появления таблицы супергероев — это дата без дня. Я решил использовать анонимный внутренний метод для реализации cellrendrer для форматирования даты.

TableColumn dateColumn = superHeroTable.getColumn(SuperHero#getFirstAppearance().getName());

// in-line cell renderer for the date column of the superhero table
dateColumn.setCellRenderer(#(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
if(isSelected){
dateRenderer.setBackground(UIManager.getColor("Table.selectionBackground"));
}else{
dateRenderer.setBackground(UIManager.getColor("Table.background"));
}
dateRenderer.setText(sdfDateColumn.format((Date) value));
return dateRenderer;
});

В целом я должен сказать, что мне нравится FCM. Даже в его неполном состоянии я чувствую, что это все еще шаг вперед. Метод и полевые литералы были очень удобны и полезны. Я вижу себя создающим обобщенные классы адаптеров вокруг этой функциональности. Как я уже говорил, я не фанат встроенного кода. Я также не склонен к внутренним классам. Но синтаксис анонимного внутреннего метода казался достаточно простым. Также я предпочитаю использовать синтаксис # для передачи метода в invokeLater.

Мои примеры включали бин и связанные с ним методы. Однако в настоящее время нет способа указать, что метод, используемый в качестве параметра, происходит из какого-либо определенного класса. Конечно, было бы ошибкой передать FCMMethodListModel

System.out # Println (объекта). Я думаю, что это один из пунктов в списке вещей, которые можно сделать для FCM, но я не уверен.

Я сделал
исходный код для этой демонстрации доступным на Google Docs. Просто помните, что вам нужна
прототипная реализация FCM для его запуска.

Наконец я хотел бы поблагодарить
Стивену за всю его тяжелую работу по созданию этого прототипа. Было весело поэкспериментировать с этим.

Примечание.
Это код демо-уровня. Это было написано, чтобы поиграть с FCM, и такие модели не так надежны, как могли бы быть. Их задача — адаптировать неизменный список bean-компонентов с использованием литералов метода FCM. Возможно, я когда-нибудь еще вернусь к FCMTableModel, чтобы показать, как его можно улучшить. В настоящее время они не поддерживают события. Также я не уверен, что средство визуализации ячеек было хорошим выбором для примера анонимного внутреннего метода. Если вы читаете javadoc для DefaultTableCellRenderer, это говорит о переопределении некоторых методов JLabel по соображениям производительности.