未能为JavaFX的TableColumn泛化一些常见代码

未能为JavaFX的TableColumn泛化一些常见代码,java,generics,inheritance,javafx,types,Java,Generics,Inheritance,Javafx,Types,在中,TableColumn的3个实例所做的事情基本相同。因此,我想编写一个新类SuperColumn extensed TableColumn,以处理TableColumn的常规过程。因此,我尝试在构造函数中使用以下通用代码: public class SuperColumn<Person, V> extends TableColumn<Person, V>{ String columnHead; int columnWidth; String

在中,
TableColumn
的3个实例所做的事情基本相同。因此,我想编写一个新类
SuperColumn extensed TableColumn
,以处理
TableColumn
的常规过程。因此,我尝试在构造函数中使用以下通用代码:

public class SuperColumn<Person, V> extends TableColumn<Person, V>{
    String columnHead;
    int columnWidth;
    String variableName;

    public SuperColumn(String columnHead, int columnWidth, String variableName) {
        super();
        this.setText(columnHead);
        this.setMinWidth(columnWidth);      
        this.setCellValueFactory(new PropertyValueFactory<Person, V>(variableName));        
        this.setOnEditCommit(
                new EventHandler<CellEditEvent<Person, V>>() {
                    @Override
                    public void handle(CellEditEvent<Person, V> t) {
                        ((Person) t.getTableView().getItems().get(
                                t.getTablePosition().getRow())
                                ).setEmail(t.getNewValue());
                    }
                });   
    }

}
公共类超级列扩展了TableColumn{
弦柱头;
int列宽;
字符串变量名;
公共超级列(字符串列头、int-columnWidth、字符串变量名){
超级();
this.setText(columnHead);
此.setMinWidth(columnWidth);
这个.setCellValueFactory(新的PropertyValueFactory(variableName));
此文件为.setOnEditCommit(
新的EventHandler(){
@凌驾
公共无效句柄(CellEditEvent t){
((Person)t.getTableView().getItems().get(
t、 getTablePosition().getRow())
).setEmail(t.getNewValue());
}
});   
}
}
在上面,我希望
setEmail
依赖于
variableNew
。也就是说,如果
variableNew
的“setEmail”
,那么我们将调用
setEmail(t.getNewValue())
。如果
variableNew
的“setFirstName”
,那么我们将调用
setFirstName(t.getNewValue())

我怎样才能做到这一点

即使是对于上面的代码,我也收到了错误消息“方法setEmail(V)对于类型Person是未定义的”。

公共类超级列扩展了TableColumn{
公共超级列(字符串列头、int-columnWidth、字符串变量名){
超级();
this.setText(columnHead);
此.setMinWidth(columnWidth);
这个.setCellValueFactory(新的PropertyValueFactory(variableName));
这个.setOnEditCommit(t->{
int row=t.getTablePosition().getRow();
Person=t.getTableView().getItems().get(行);
V value=t.getNewValue();
试一试{
方法Method=person.getClass().getMethod(“set”+variableName,value.getClass());
调用(人、值);
}捕获(NoSuchMethodException | IllegalacessException | InvocationTargetException e){
e、 printStackTrace();
}
});
}
}
并称之为:

SuperColumn<Person, String> column = new SuperColumn<>("Email", 100, "email");
SuperColumn column=newsupercolumn(“Email”,100,“Email”);

就一般编程风格而言,仅为了配置所创建的实例而对类进行子类化不是特别好的做法,除非您提供的是基类不提供的附加功能。如果子类除了有一个构造函数之外什么都不做,这就是这个反模式的一个特殊指示器。我将在这里展示的一种更好的方法是使用某种创造性模式,它可能与为您创建实例的一些静态方法一样简单。(更高级的实现将使用各种工厂模式。)

无论如何,您尝试执行的不依赖于反射的版本(我稍后将解释为什么我不喜欢反射方法)需要您传入某种函数,该函数处理特定
人员
实例的新(编辑)值。A适用于此:

public class TableColumns {
    public static <V> TableColumn<Person,V> create(String columnHead, int columnWidth, String variableName, BiConsumer<Person, V> setter) {
        TableColumn<Person, V> column = new TableColumn<>(columnHead);
        column.setMinWidth(columnWidth);
        column.setCellValueFactory(new PropertyValueFactory<>(variableName));
        column.setOnEditCommit(t -> {
            int row = t.getTablePosition().getRow();
            Person person = t.getTableView().getItems().get(row);
            V value = t.getNewValue();
            setter.consume(person, value);
        });
        return column ;
    }

}
使用此版本的
Person
类,表列只需访问特定属性即可获取值(在
cellValueFactory
中)和设置值(在
onEditCommit
处理程序中)。因此,您所需要的只是一个函数,它为给定的
Person
实例提供属性。您还可以轻松地将其概括为
S
类型的参数化行值:

public class TableColumns {

    public static <S,T> TableColumn<S,T> create(String title, int width, Function<S, Property<T>> property) {
        TableColumn<S,T> column = new TableColumn<>(title);
        column.setMinWidth(width);
        column.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        column.setOnEditCommit(t -> {
            int row = t.getTablePosition().getRow();
            S rowValue = t.getTableView().getItems().get(row);
            T value = t.getNewValue();
            property.apply(rowValue).setValue(value);
        });
        return column ;
    }

    // other creational methods...
}

但是,我要再次强调,这不是继承的好用途,您应该更喜欢基于方法(或基于工厂)的方法。

最后,我设法结合了LêHoáng D的思想ững(即使用
函数
)和James_D(即使用
TableColumns.Create()
),我得到:

import java.util.function.Function;

import javafx.beans.property.Property;
import javafx.scene.control.TableColumn;

public class TableColumns<S,T> {

    public static <S, T> TableColumn<S,T> create(String columnHead, int columnWidth, Function<S, Property<T>> myFunc) {
    
        TableColumn<S, T> myColumn = new TableColumn<>(columnHead);

        myColumn.setMinWidth(columnWidth);
        myColumn.setCellValueFactory(cellData -> myFunc.apply(cellData.getValue())); // binding column (i.e. this) and the variable
        myColumn.setOnEditCommit(event -> {
            int row = event.getTablePosition().getRow();
            S rowValue = event.getTableView().getItems().get(row);
            T newValue = event.getNewValue();
            myFunc.apply(rowValue).setValue(newValue);
        });
        return myColumn;
    }

}
import java.util.function.function;
导入javafx.beans.property.property;
导入javafx.scene.control.TableColumn;
公共类表列{
公共静态TableColumn创建(String columnHead、int columnWidth、函数myFunc){
TableColumn myColumn=新的TableColumn(columnHead);
myColumn.setMinWidth(columnWidth);
myColumn.setCellValueFactory(cellData->myFunc.apply(cellData.getValue());//绑定列(即this)和变量
myColumn.setOnEditCommit(事件->{
int row=event.getTablePosition().getRow();
S rowValue=event.getTableView().getItems().get(行);
T newValue=event.getNewValue();
myFunc.apply(rowValue).setValue(newValue);
});
返回菌柱;
}
}

该示例是(而且一直是)垃圾—公开属性,然后就不需要编辑处理程序了。不管怎么说,基本的OO命令不会因为配置原因而扩展——你是在错误的轨道上,你会考虑删除(或者移动到一个大的No.No不)的扩展选项吗?对其他人表示完全赞同,所以我想向上投票:)@kleopatra是的,在回答提出的问题时总是有点犹豫,或者在“更好的设计”方面偏离了正轨……@James_D,非常感谢你的回答。如果不允许我修改存储“TableColumns”的原始库的话“,是否仍然可以添加
create
方法?如果我为
TableColumns
创建一个新文件,我将覆盖原始定义。@H42我不明白你的意思
TableColumns
正是我选择的类名。@James\u D,谢谢,我以前把
TableColumns
和<
public class Person {

    private final StringProperty email = new SimpleStringProperty();

    public StringProperty emailProperty() {
        return email ;
    }

    public final String getEmail() {
        return emailProperty().get();
    }

    public final void setEmail(String email) {
        emailProperty().set(email);
    }

    // similarly for other properties

}
public class TableColumns {

    public static <S,T> TableColumn<S,T> create(String title, int width, Function<S, Property<T>> property) {
        TableColumn<S,T> column = new TableColumn<>(title);
        column.setMinWidth(width);
        column.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        column.setOnEditCommit(t -> {
            int row = t.getTablePosition().getRow();
            S rowValue = t.getTableView().getItems().get(row);
            T value = t.getNewValue();
            property.apply(rowValue).setValue(value);
        });
        return column ;
    }

    // other creational methods...
}
TableColumn<Person, String> emailColumn = 
    TableColumns.create("Email", 100, Person::emailProperty);
public class SuperColumn<S,T> extends TableColumn<S,T> {

    public SuperColumn(String title, int width, Function<S, Property<T>> property) {
        super(title);
        setMinWidth(width);
        setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        setOnEditCommit(event -> {
            int row = event.getTablePosition().getRow();
            S rowValue = event.getTableView().getItems().get(row);
            T value = event.getNewValue();
            property.apply(rowValue).setValue(value);
        });
    }
}
import java.util.function.Function;

import javafx.beans.property.Property;
import javafx.scene.control.TableColumn;

public class TableColumns<S,T> {

    public static <S, T> TableColumn<S,T> create(String columnHead, int columnWidth, Function<S, Property<T>> myFunc) {
    
        TableColumn<S, T> myColumn = new TableColumn<>(columnHead);

        myColumn.setMinWidth(columnWidth);
        myColumn.setCellValueFactory(cellData -> myFunc.apply(cellData.getValue())); // binding column (i.e. this) and the variable
        myColumn.setOnEditCommit(event -> {
            int row = event.getTablePosition().getRow();
            S rowValue = event.getTableView().getItems().get(row);
            T newValue = event.getNewValue();
            myFunc.apply(rowValue).setValue(newValue);
        });
        return myColumn;
    }

}