前言:我试图在不需要样板代码的情况下解决我的问题。我可以通过复制/粘贴和重构代码轻松解决这个问题,但是这种问题应该可以用模型驱动的方法解决,因为设计明显重现。
我有一个包含四种不同对象类型的数据库应用程序,它们将用作另一个中心对象的参数。
所有四个字段在结构上都相同:一个自动生成的主键和一个VARCHAR
字段。这些字段需要由最终用户编辑,因此我设计了这个屏幕:
不是为此制作四个不同的屏幕,我认为制作这个由四种不同对象类型使用的屏幕会很好。为了做到这一点,我(显然,对吗?)需要创建一个抽象的对象(我称之为)StringField
,它可以通过四种子类型实现:Status
,Type
,{{1 }和Classification
。如前所述,因为每个对象在结构上都是相同的,并且以相同的方式读/写数据库,所以抽象对象似乎是合乎逻辑的。所以,我提出了这个目标:
Designation
子类实现如下(例如):
public abstract class StringField {
private final int id;
private final String value;
private final String fieldname;
private final String tablename;
public StringField(int id, String value, String fieldname, String tablename) {
this.id = id;
this.value = value;
this.fieldname = fieldname;
this.tablename = tablename;
}
public String getValue() {
return value;
}
public int getId() {
return id;
}
@Override
public int hashCode() {
int hash = 5;
hash = 59 * hash + this.id;
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return this.id == ((StringField)obj).id;
}
@Override
public String toString() {
return value;
}
public int insertValue(DB db, String value) throws WrappedSQLException {
... // DB code here
}
public void updateValue(DB db, String value, int id) throws WrappedSQLException {
... // DB code here
}
public void deleteValue(DB db, int id) throws WrappedSQLException {
... // DB code here
}
}
撇开:
public class Type extends StringField { public Type(int id, String value) { super(id, value, "type", "customer_type"); } } public class Classification extends StringField { public Classification (int id, String value) { super(id, value, "classification", "customer_classification"); } }
和String fieldname
的原因 构造函数是Java不允许静态抽象 领域。因此,它们需要由类别手动提供 使用超级类型。不幸的是,这会阻止String tablename
,insert
和update
方法也被声明为delete
。 如果Java允许static
,我怀疑我会问这个问题 因为我只会制作static abstract
,insert
和update
方法static以delete
和fieldname
作为抽象静态 字段,将被强制由子类型实现 静态时尚,然后可以静态引用 超类,然后可以通过每个超静态调用 亚型。基本上,它可能看起来像这样:超类型:
tablename
亚型:
public abstract class StringField { private final int id; private final String value; public StringField(int id, String value) { this.id = id; this.value = value; } public static abstract String fieldname; public static abstract String tablename; public static int insertValue(String value) { // Insert code, returns auto-generated primary key // ... // This code will use the static fields `fieldname` and `tablename`. // ... return -1; } public static void updateValue(String value, int id) { // Update code... // ... // This code will use the static fields `fieldname` and `tablename`. // ... } public static void deleteValue(int id) { // Delete code... // ... // This code will use the static fields `fieldname` and `tablename`. // ... } }
并使用如下:
static class Type extends StringField { public Type(int id, String value) { super(id, value); } public static String fieldname = "type"; public static String tablename = "customer_type"; }
好的,足够抱怨Java不允许Type.insertValue(newValue);
。这是我到目前为止完整的,(几乎)可编译的代码,它说明了我的方法:
static abstract
然而,这会引发错误:
@SuppressWarnings("serial")
public class StringFieldEditor extends JPanel {
final Collection<StringField> fields;
String fieldname;
public StringFieldEditor(Collection<StringField> fields, String fieldname) {
super(new GridBagLayout());
this.fields = fields;
this.fieldname = fieldname;
GridBagConstraints gridBagConstraints;
JButton addNew_button = new JButton();
JButton delete_button = new JButton();
JButton edit_button = new JButton();
JLabel jLabel1 = new JLabel();
JList<StringField> jList = new JList<>();
jList.setModel(new DefaultListModel<>());
jList.setListData(fields.toArray(new StringField[fields.size()]));
JScrollPane jScrollPane1 = new JScrollPane();
jScrollPane1.setViewportView(jList);
jLabel1.setText("Customer " + fieldname + " Editor");
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new Insets(11, 10, 0, 0);
add(jLabel1, gridBagConstraints);
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 5;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.ipadx = 178;
gridBagConstraints.ipady = 206;
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new Insets(6, 10, 0, 10);
add(jScrollPane1, gridBagConstraints);
addNew_button.setText("Add New");
addNew_button.addActionListener((ActionEvent evt) -> {
// Add New Task
});
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new Insets(6, 10, 11, 0);
add(addNew_button, gridBagConstraints);
edit_button.setText("Edit");
edit_button.addActionListener((ActionEvent evt) -> {
// Edit Task
});
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new Insets(6, 6, 11, 0);
add(edit_button, gridBagConstraints);
delete_button.setText("Delete");
delete_button.addActionListener((ActionEvent evt) -> {
// Delete Task
});
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 4;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new Insets(6, 6, 11, 10);
add(delete_button, gridBagConstraints);
}
static class Type extends StringField {
public Type(int id, String value) {
super(id, value, "type", "customer_type");
}
}
public abstract class StringField {
private final int id;
private final String value;
private final String fieldname;
private final String tablename;
public StringField(int id, String value, String fieldname, String tablename) {
this.id = id;
this.value = value;
this.fieldname = fieldname;
this.tablename = tablename;
}
public String getValue() {
return value;
}
public int getId() {
return id;
}
@Override
public int hashCode() {
int hash = 5;
hash = 59 * hash + this.id;
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return this.id == ((StringField)obj).id;
}
@Override
public String toString() {
return value;
}
public int insertValue(String value) {
// Insert code, returns auto-generated primary key
// ...
// ...
return -1;
}
public void updateValue(String value, int id) {
// Update code...
// ...
// ...
}
public void deleteValue(int id) {
// Delete code...
// ...
// ...
}
}
public static void main(String[] args) {
LinkedList<Type> types = new LinkedList<>();
types.add(new Type(1, "Type 1"));
types.add(new Type(2, "Type 2"));
types.add(new Type(3, "Type 3"));
JFrame frame = new JFrame();
frame.add(new StringFieldEditor(types, "type"));
frame.pack();
frame.setLocationByPlatform(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
但改变:
incompatible types: LinkedList<Type> cannot be converted to Collection<StringFieldEditor.StringField>
到
final Collection<StringField> fields;
String fieldname;
public StringFieldEditor(Collection<StringField> fields, String fieldname) {
尝试将数据加载到 final Collection<? extends StringField> fields;
String fieldname;
public StringFieldEditor(Collection<? extends StringField> fields, String fieldname) {
时,会导致问题(JList
需要toArray
类型的值,但如果我不知道我正在使用的确切类型,我无法提供新的T
类型数组。
另外,我预见到尝试以非子类特定方式引用非静态插入,更新和删除方法的问题。
我的问题:
T
个方法/字段的事实,是否有一个很好的解决方法?static abstract
方法提供可用的数组?