Какой подход относится к шаблону заводского проектирования?
Да, так оно и есть. Вся цель шаблона фабрики позволяет классу, использующему его (TableView
), создавать экземпляры классов, придерживающихся определенного контракта (TableCell
), но скрывая от него конкретную реализацию.
Рабочий процесс показан на диаграмме на этой странице: http://www.oodesign.com/factory-pattern.html
Просто заменить Client
с TableView
и Product
с TableCell
...
Это позволяет создавать классы многократного использования для cellFactory
и cellValueFactory
без необходимости менять что-либо расширение TableView
/TableColumn
. (Просто взгляните на javafx.scene.control.cell
package, у большинства (или даже всех) ячеек есть статический метод создания фабрики для своего типа, которые работают независимо от TableView
элементов и могут использоваться вместе, например, с помощью PropertyValueFactory
).
Как создать пользовательскую фабрику ячеек для каждой ячейки таблицы TableColumn в зависимости от содержимого ячейки?
У вас нет. Вы пишете ячейку таблицы, которая решает ее компоновку в зависимости от содержимого, переданного путем изменения свойств и свойств объекта text
и graphic
. когда элемент изменяется (item
владелец дома или updateItem
метод).
Пример для клеток, воспроизводящих классов, показывая экземпляр, созданный с помощью конструктора по умолчанию:
column1.setCellFactory(v -> new TableCell<Class<? extends Node>, Class<? extends Node>>() {
@Override
protected void updateItem(Class<? extends Node> item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
try {
setGraphic(item.getConstructor().newInstance());
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | InvocationTargetException ex) {
setGraphic(null);
}
}
}
});
Это предполагает, что вы можете решить, макет, учитывая значение элемента.
Если вы не можете спроектировать чистый код с этим подходом, рассмотреть вопрос об объединении его с шаблоном стратегии, то есть пусть ваши детали решают макет TableCell
:
@FunctionalInterface
public interface TableCellLayouter {
void layoutCell(TableCell<?, ?> cell);
}
// the content could be more complex of course
TableView<TableCellLayouter> tv = new TableView<>(FXCollections.observableArrayList(
cell -> {
cell.setText(null);
cell.setGraphic(new Rectangle(100, 100));
},
cell -> {
cell.setGraphic(null);
cell.setText("Hello world!");
},
cell -> {
cell.setGraphic(new Circle(20));
cell.setText("circle");
}));
TableColumn<TableCellLayouter, TableCellLayouter> column1 = new TableColumn<>("a");
column1.setCellValueFactory(c -> Bindings.createObjectBinding(() -> c.getValue()));
column1.setCellFactory(v -> new TableCell<TableCellLayouter, TableCellLayouter>() {
@Override
protected void updateItem(TableCellLayouter item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
item.layoutCell(this);
}
}
});
OK, если бы я правильно поняли, изменение фабрики не является решением, но применить изменение к методу Cell on update() - единственный способ. В моем случае я отображаю только текст в ячейке, так что поведение редактирования должно быть разным, в зависимости от типа объекта в ячейке oi должны генерировать другое текстовое поле с различным поведением, когда я редактирую другую ячейку, и я должен определить ее на startEdit() не так ли? – Doremus
@Doremus: Да, ячейки могут быть использованы повторно для эффективности, но вы решаете на заводе, какой класс ячеек вы используете или каким-то образом модифицируете ячейку. Метод 'updateItem' - это не единственный способ сделать это. Регистрация слушателя в свойство ['item' ячейки] (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/Cell.html#itemProperty) также может работать и может быть полезным , если вам нужно отменить изменения в зависимости от элемента, ранее показанного в ячейке. – fabian
tks для вашего ответа @fabian! Последний вопрос, этот слушатель по свойству item, где его определить? На моей фабрике ячеек? в классе, где я инициализирую свое табличное представление? – Doremus