我在一个项目中工作,在该项目中,我们有多个域类来对业务数据进行建模。这些类是简单的POJO,我必须使用它们显示几个表。例如,考虑此类:
public class Customer {
private Long id;
private Date entryDate;
private String name;
private String address;
private String phoneNumber;
public Customer(Long id, Date entryDate, String name, String address, String phoneNumber) {
this.id = id;
this.entryDate = entryDate;
this.nombre = name;
this.domicilio = address;
this.telefono = phoneNumber;
}
// Getters and setters here
}
然后,我创建了自己的表模型,该表模型从AbstractTableModel扩展,以便直接与Customer
类一起使用:
public class CustomerTableModel extends AbstractTableModel {
private final List<String> columnNames;
private final List<Customer> customers;
public CustomerTableModel() {
String[] header = new String[] {
"Entry date",
"Name",
"Address",
"Phone number"
};
this.columnNames = Arrays.asList(header);
this.customers = new ArrayList<>();
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: return Date.class;
case 1: return String.class;
case 2: return String.class;
case 3: return String.class;
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Customer customer = getCustomer(rowIndex);
switch (columnIndex) {
case 0: return customer.getEntryDate();
case 1: return customer.getName();
case 2: return customer.getAddress();
case 3: return customer.getPhoneNumber();
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex < 0 || columnIndex >= getColumnCount()) {
throw new ArrayIndexOutOfBoundsException(columnIndex);
} else {
Customer customer = getCustomer(rowIndex);
switch (columnIndex) {
case 0: customer.setEntryDate((Date)aValue); break;
case 1: customer.setName((String)aValue); break;
case 2: customer.setAddress((String)aValue); break;
case 3: customer.setPhoneNumber((String)aValue); break;
}
fireTableCellUpdated(rowIndex, columnIndex);
}
}
@Override
public int getRowCount() {
return this.customers.size();
}
@Override
public int getColumnCount() {
return this.columnNames.size();
}
@Override
public String getColumnName(int columnIndex) {
return this.columnNames.get(columnIndex);
}
public void setColumnNames(List<String> columnNames) {
if (columnNames != null) {
this.columnNames.clear();
this.columnNames.addAll(columnNames);
fireTableStructureChanged();
}
}
public List<String> getColumnNames() {
return Collections.unmodifiableList(this.columnNames);
}
public void addCustomer(Customer customer) {
int rowIndex = this.customers.size();
this.customers.add(customer);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void addCustomers(List<Customer> customerList) {
if (!customerList.isEmpty()) {
int firstRow = this.customers.size();
this.customers.addAll(customerList);
int lastRow = this.customers.size() - 1;
fireTableRowsInserted(firstRow, lastRow);
}
}
public void insertCustomer(Customer customer, int rowIndex) {
this.customers.add(rowIndex, customer);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void deleteCustomer(int rowIndex) {
if (this.customers.remove(this.customers.get(rowIndex))) {
fireTableRowsDeleted(rowIndex, rowIndex);
}
}
public Customer getCustomer(int rowIndex) {
return this.customers.get(rowIndex);
}
public List<Customer> getCustomers() {
return Collections.unmodifiableList(this.customers);
}
public void clearTableModelData() {
if (!this.customers.isEmpty()) {
int lastRow = customers.size() - 1;
this.customers.clear();
fireTableRowsDeleted(0, lastRow);
}
}
}
到目前为止,一切都很好。但是,此方法至少有两个问题:
由于我必须为每个类实现一个表模型,因此我将生成大量重复代码以实质上完成三件事:定义适当的表头,向/从基础结构(列表)添加/删除对象,覆盖二者setValueAt()
以及getValueAt()
与用户定义的对象一起使用的方法。
假设我有完全相同的客户列表,但是我必须在两个不同的表中使用不同的标题或数据来显示此列表。我将不得不继承我的表模型,并覆盖为了满足此要求而需要覆盖的所有内容。一点都不优雅。
问题: 有什么方法可以摆脱样板代码,使我的表模型灵活且可重用?
像其他Swing模型(即DefaultComboBoxModel,DefaultListModel)一样,我们可以使用泛型来创建灵活且可重用的表模型,还提供与用户定义的POJO一起使用的API。
该表模型将具有以下特殊功能:
AbstractTableModel
利用表模型事件处理的优势扩展而来。CustomerTableModel
上面显示的不同,此表模型必须是抽象的,因为它不能重写getValueAt()
方法:仅仅因为我们不知道该表模型将处理的类或数据类型,重写上述方法的任务留给了子类。setValueAt()
实现AbstractTableModel
。这是有道理的,因为isCellEditable()
它也从该类继承并始终返回false
。getColumnClass()
也被继承,并且始终返回Object.class
。这些功能使此表模型真正易于实现,具体取决于我们的要求:
getValueAt()
和getColumnClass()
(这是推荐的,但不是强制性的)。isCellEditable()
和setValueAt()
。让我们看一下表模型的代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.table.AbstractTableModel;
/**
* Abstract base class which extends from {@code AbstractTableModel} and
* provides an API to work with user-defined POJO's as table rows. Subclasses
* extending from {@code DataObjectTableModel} must implement
* {@code getValueAt(row, column)} method.
* <p />
* By default cells are not editable. If those have to be editable then
* subclasses must override both {@code isCellEditable(row, column)} and
* {@code setValueAt(row, column)} methods.
* <p />
* Finally, it is not mandatory but highly recommended to override
* {@code getColumnClass(column)} method, in order to return the appropriate
* column class: default implementation always returns {@code Object.class}.
*
* @param <T> The class handled by this TableModel.
* @author dic19
*/
public abstract class DataObjectTableModel<T> extends AbstractTableModel {
private final List<String> columnNames;
private final List<T> data;
public DataObjectTableModel() {
this.data = new ArrayList<>();
this.columnNames = new ArrayList<>();
}
public DataObjectTableModel(List<String> columnIdentifiers) {
this();
if (columnIdentifiers != null) {
this.columnNames.addAll(columnIdentifiers);
}
}
@Override
public int getRowCount() {
return this.data.size();
}
@Override
public int getColumnCount() {
return this.columnNames.size();
}
@Override
public String getColumnName(int columnIndex) {
return this.columnNames.get(columnIndex);
}
public void setColumnNames(List<String> columnNames) {
if (columnNames != null) {
this.columnNames.clear();
this.columnNames.addAll(columnNames);
fireTableStructureChanged();
}
}
public List<String> getColumnNames() {
return Collections.unmodifiableList(this.columnNames);
}
public void addDataObject(T dataObject) {
int rowIndex = this.data.size();
this.data.add(dataObject);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void addDataObjects(List<T> dataObjects) {
if (!dataObjects.isEmpty()) {
int firstRow = data.size();
this.data.addAll(dataObjects);
int lastRow = data.size() - 1;
fireTableRowsInserted(firstRow, lastRow);
}
}
public void insertDataObject(T dataObject, int rowIndex) {
this.data.add(rowIndex, dataObject);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void deleteDataObject(int rowIndex) {
if (this.data.remove(this.data.get(rowIndex))) {
fireTableRowsDeleted(rowIndex, rowIndex);
}
}
public void notifyDataObjectUpdated(T domainObject) {
T[] elements = (T[])data.toArray();
for (int i = 0; i < elements.length; i++) {
if(elements[i] == domainObject) {
fireTableRowsUpdated(i, i);
}
}
}
public T getDataObject(int rowIndex) {
return this.data.get(rowIndex);
}
public List<T> getDataObjects(int firstRow, int lastRow) {
List<T> subList = this.data.subList(firstRow, lastRow);
return Collections.unmodifiableList(subList);
}
public List<T> getDataObjects() {
return Collections.unmodifiableList(this.data);
}
public void clearTableModelData() {
if (!this.data.isEmpty()) {
int lastRow = data.size() - 1;
this.data.clear();
fireTableRowsDeleted(0, lastRow);
}
}
}
因此,采用此表模型和Customer
类,一个完整的实现将如下所示:
String[] header = new String[] {"Entry date", "Name", "Address", "Phone number"};
DataObjectTableModel<Customer> model = new DataObjectTableModel<>(Arrays.asList(header)) {
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: return Date.class;
case 1: return String.class;
case 2: return String.class;
case 3: return String.class;
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Customer customer = getDataObject(rowIndex);
switch (columnIndex) {
case 0: return customer.getEntryDate();
case 1: return customer.getName();
case 2: return customer.getAddress();
case 3: return customer.getPhoneNumber();
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex < 0 || columnIndex >= getColumnCount()) {
throw new ArrayIndexOutOfBoundsException(columnIndex);
} else {
Customer customer = getDataObject(rowIndex);
switch (columnIndex) {
case 0: customer.setEntryDate((Date)aValue); break;
case 1: customer.setName((String)aValue); break;
case 2: customer.setAddress((String)aValue); break;
case 3: customer.setPhoneNumber((String)aValue); break;
}
fireTableCellUpdated(rowIndex, columnIndex);
}
}
};
如我们所见,在几行代码(LOC <50)中,我们有一个完整的实现。
只要实体具有公共获取者和设置者,它就起作用。与JPA实现不同,此表模型不适用于反射,因此我们必须使用类的公共接口来实现getValueAt()
和setValueAt()
方法来访问对象属性。
不,不是。我们将不得不将结果集包装到域类中,并使用如上所述的类提供的接口。
是的,它确实。再次使用class提供的界面。例如,让java.io.File
我们上课,我们可以实现以下表模型实现:
String[] header = new String[] {
"Name",
"Full path",
"Last modified",
"Read",
"Write",
"Execute",
"Hidden",
"Directory"
};
DataObjectTableModel<File> model = new DataObjectTableModel<File>(Arrays.asList(header)) {
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: return String.class;
case 1: return String.class;
case 2: return Date.class;
case 3: return Boolean.class;
case 4: return Boolean.class;
case 5: return Boolean.class;
case 6: return Boolean.class;
case 7: return Boolean.class;
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
File file = getDataObject(rowIndex);
switch (columnIndex) {
case 0: return file.getName();
case 1: return file.getAbsolutePath();
case 2: return new Date(file.lastModified());
case 3: return file.canRead();
case 4: return file.canWrite();
case 5: return file.canExecute();
case 6: return file.isHidden();
case 7: return file.isDirectory();
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
};
介绍 任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量避免使用这些模式,因为或多或少有带来一些问题;第二排是推荐篇,指的是推荐大家使用的模式,一般不会有什么问题。 模式1:默认模式 代码复用大家常用的默认模式,往往是有问题的,该模式使用Parent()的
本文向大家介绍Python自定义scrapy中间模块避免重复采集的方法,包括了Python自定义scrapy中间模块避免重复采集的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python自定义scrapy中间模块避免重复采集的方法。分享给大家供大家参考。具体如下: 希望本文所述对大家的Python程序设计有所帮助。
在上面,我有类似的10个if条件,如何避免上面的重复代码?我需要使用任何Java8个函数类作为参数来避免重复代码(或者)必须使用任何额外的泛型代码吗?
我正在设计一个名为unlink Node的非静态无效方法,它将节点n作为参数。它应该确保节点与它之前和之后的节点解除链接。它需要改变n后节点的prev和n前节点的下一个。目前,当我运行它时,我得到了错误 第111行n.getPrev(). Next=null; 尽管我已经输入了语句,以确保如果n是尾部,则不访问它的上一个,如果是头部,则不访问它的下一个,以确保没有访问null。 方法如下: 以及设
我们有一个报告编写工具,我们正在尝试添加搜索功能。基本上,用户可以输入一个问题,并根据句子中的标准返回一份报告。我们正在尽可能地保持开放性,不需要特定的句子结构,这就是为什么我们想尝试OpenNLP-NER。 例如: “上季度的艺术出勤率是多少?” 标记为: 我们试着用不同的部门,不同的过滤器等提出不同的问题。。我们还没有达到15k,只有14.6k,所以我们还在努力。 就分析问题而言,这是问题的开
如果您是一位经验丰富的ML开发人员,而且ML Kit的预训练的模型不能满足您的需求,您可以通过ML Kit使用定 的TensorFlow Lite模型。 使用Firebase托管您的TensorFlow Lite模型或将其与您的应用程序打包在一起。然后,使用ML Kit SDK来使用您的自定义模型的最佳版本构建应用。如果您使用Firebase托管您的模型,ML Kit会自动更新您的用户的所用版本。