Java 属性的属性有意义吗?

Java 属性的属性有意义吗?,java,javafx,javafx-2,reactfx,Java,Javafx,Javafx 2,Reactfx,因为这是一个关于设计的问题,我将从我拥有的和我想要的开始 我有一个使用构图的设计。单元格对象包含形状和背景对象(本例中为自定义对象)。这两个数据库中的每一个都有自己的数据来定义它们。下面是代码中的示例: class Cell { Shape shape; Background background; class Shape { int size; Color color; Point location;

因为这是一个关于设计的问题,我将从我拥有的和我想要的开始

我有一个使用构图的设计。
单元格
对象包含
形状
背景
对象(本例中为自定义对象)。这两个数据库中的每一个都有自己的数据来定义它们。下面是代码中的示例:

class Cell {

    Shape shape;
    Background background;

    class Shape {

        int size;
        Color color;
        Point location;
        //...
    }

    class Background {

        Color color;
        String name;
        CoverType type;
        //...
    }
}
我也有一个GUI,需要表示许多单元格,我已经写了如何做到这一点(如何使用颜色、大小等在屏幕上创建我想要的内容)。它包括CellRepresentation、ShapeRepresentation和BackgroundRepresentation等类,它们的显示属性绑定到数据属性(我认为这称为模型和视图)

我希望能够通过更改上述数据来表示GUI中的更改:

  • 用户可以(例如)右键单击形状并设置其颜色。因此,上面的数据会发生变化,而变化需要反映在GUI中
  • 用户还可以更改整个形状(例如,从另一个单元格复制粘贴)。甚至是整个牢房。这些更改也需要反映在GUI中
我的问题是哪些类成员需要是我绑定到的JavaFX属性

以下是我的想法:“叶”属性(大小、颜色、位置…)必须是属性,以便我可以将GUI属性绑定到它们。但是我是否也需要创建形状和背景对象属性?只有其属性在屏幕上具有“实际”表示。理想情况下,我希望如果形状发生变化,那么它的所有属性都会告诉绑定它们可能发生了变化(可能颜色没有变化,但大小有变化)。但是它不是这样工作的-即使形状的颜色可以在形状改变时改变,颜色属性也不会告诉任何与它相关的东西它改变了

同样的道理也适用于在有许多单元格的大图片中使单元格成为属性,以此类推:属性的属性委派更改

因此,我想让形状和背景也具有属性,并向它们注册一个
invalizationlistener
,以更新它们的属性。这似乎是不对的,因为我认为有了所有对属性的支持,就会有一种方法来实现我想要的


有人能推荐一种方法吗?

仅使用标准的JavaFXAPI,您就可以利用这些方法来观察“属性的属性”

例如:

import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.paint.Color;

public class Cell {

    private final ObjectProperty<Shape> shape = new SimpleObjectProperty<>(new Shape());


    public final ObjectProperty<Shape> shapeProperty() {
        return this.shape;
    }




    public final Cell.Shape getShape() {
        return this.shapeProperty().get();
    }




    public final void setShape(final Cell.Shape shape) {
        this.shapeProperty().set(shape);
    }


    public static class Shape {

        private final IntegerProperty size = new SimpleIntegerProperty(0);
        private final ObjectProperty<Color> color = new SimpleObjectProperty<>(Color.BLACK);
        public final IntegerProperty sizeProperty() {
            return this.size;
        }

        public final int getSize() {
            return this.sizeProperty().get();
        }

        public final void setSize(final int size) {
            this.sizeProperty().set(size);
        }

        public final ObjectProperty<Color> colorProperty() {
            return this.color;
        }

        public final javafx.scene.paint.Color getColor() {
            return this.colorProperty().get();
        }

        public final void setColor(final javafx.scene.paint.Color color) {
            this.colorProperty().set(color);
        }

    }


    public static void main(String[] args) {
        Cell cell = new Cell();
        Bindings.selectInteger(cell.shapeProperty(), "size").addListener(
                (obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));
        cell.getShape().setSize(10);
        cell.setShape(new Shape());
        Shape s = new Shape();
        s.setSize(20);
        cell.setShape(s);
    }

}
这个API有一点遗留的感觉,因为它依赖于以字符串形式传递属性名,因此不是类型安全的,不能在编译时进行检查。此外,如果任何中间属性为null(例如,在本例中,如果
cel.getShape()
返回null),则绑定会生成恼人且冗长的警告消息(即使这应该是受支持的用例)

Tomas Mikula的实现更为现代,请参见以获取描述。使用ReactFX,可以执行以下操作:

public static void main(String[] args) {
    Cell cell = new Cell();
    Var<Number> size = Val.selectVar(cell.shapeProperty(), Shape::sizeProperty);
    size.addListener(
            (obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));

    cell.getShape().setSize(10);
    cell.setShape(new Shape());
    Shape s = new Shape();
    s.setSize(20);
    cell.setShape(s);
}
使用标准API,或

ObservableList<Cell> cellList = 
    FXCollections.observableArrayList(cell -> new Observable[] {Val.selectVar(cell.shapeProperty(), Shape::sizeProperty)});
observeListCellList=
FXCollections.observearraylist(cell->newobserveable[]{Val.selectVar(cell.shapeProperty(),Shape::sizeProperty)});

使用ReactFX。然后只需在列表中添加一个
ListChangeListener
,如果大小发生变化(或者形状更改为具有不同大小的新形状),就会收到通知。您可以根据需要在返回的数组中添加任意多个作为单元格属性(或属性的属性)的观察对象。

@zyexal我知道继承,java对我来说并不陌生。这有什么关系?您可能想看看这些方法,它们为您提供了一种绑定到“properties of properties”的方法。这个API有点“遗留”的感觉,因为它不是类型安全的或编译时可验证的。Tomas Mikula有一个更现代的实现,它实现了相同的思想,请参见。但底线是,对于任何可能发生变化的内容,以及您可能希望对这些变化做出反应的内容,您都应该使用JavaFX属性。(所以可能所有字段都是…)ReactFX似乎是一个更好的选择。我不可能在我的属性反射样式中使用字符串名称——这到处都是麻烦。谢谢@马克:我在你的问题中添加了ReactFX标签,以防更了解它的人想添加任何内容。
ObservableList<Cell> cellList = 
    FXCollections.observableArrayList(cell -> new Observable[] {Val.selectVar(cell.shapeProperty(), Shape::sizeProperty)});