在 mvvmFX 库中使用 ModelWrapper class 建模为 "domain model"

Model as a "domain model" with ModelWrapper class in mvvmFX library

我想问你关于模型和 ModelWrapper 行为的问题。根据维基百科关于 MVVM 模型组件的文章:

Model refers either to a domain model, which represents real state content (an object-oriented approach), or to the data access layer, which represents content (a data-centric approach).

我在 mvvmFX 文档和示例中寻找 ModelWrapper 使用示例,但我只找到了数据访问层模型示例。我需要将模型 classes 与业务逻辑结合使用。例如,在 setter 方法中更改 class 状态(这里的副作用用法是代码味道吗?):

    public class ModelClass {

        private int intField;        
        private String stringField;

        public int getIntField() {
          return intField;
        }

        public void setIntField(int intField) {
          if (intField == 100) {
            this.stringField = "";
          }
          this.intField = intField;
        }

        public String getStringField() {
          return familyName;
        }

        public void setStringField(String stringField) {
          this.stringField = stringField;
        }

    }

根据 ModelWrapper 文档:

The user changes the values of the viewModel properties (via the UI). The state of the underlying model instance may not be changed at this point in time! When the user clicks an Apply button (and validation is successful) copy all values from the ViewModel fields into the model instance.

如何使用这样的模型 classes,而不是两次实现业务逻辑(第一次在模型 class 中,第二次在 ViewModel class 中时间)?或者,也许我必须将业务逻辑转移到其他地方?

ModelWrapper 主要用于 Java Bean 类,没有太多逻辑。它有助于防止用户必须编写代码来将值从模型对象复制到 ViewModel 并返回。

在您的示例中,当您调用 ModelWrapper 的 commit 方法时,它将通过调用所有已注册的 setter 方法将所有值从 viewModel 属性复制到模型实例。这是按照 属性 字段注册的顺序完成的。如果您先注册了 intField-属性,则 ModelWrapper 将首先调用 setIntField 方法(在模型实例中更改 intFieldstringField),然后调用 setStringField 方法覆盖了 stringField。 但是,必须修改字段注册的顺序听起来不是一个好主意,而且很可能无法扩展到更复杂的模型 类。

所以最后我认为 ModelWrapper 不是适合您的用例的工具。在许多情况下,没有关于如何将模型 类 与 viewModel 连接的通用答案。它在很大程度上取决于预期的行为和用例。

关于 setter 中关于副作用的问题,如果这是代码异味:在我看来,使用单一方法修改多个内部字段的状态是完全没问题的。这就是 OOP 和信息隐藏的全部内容。但是,在 Java 中有 getter 和 setter 方法的约定。如果您将方法命名为 setIntField,大多数 Java 开发人员会认为此方法仅修改 intField,仅此而已。所以我建议为这种方法找到一个更好的名称,并保持 getters 和 setters 简单明了。