javajavafxmvvmmodelmvvmfx

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


I want to ask you about model and ModelWrapper behavior. According to Wikipedia article about model component of 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).

I was looking for ModelWrapper usage samples in mvvmFX documentation and examples, but I found only data access layer model sample. I need to use model classes with business logic. For example, changing class state in setter method (is the side effect usage a code smell here?):

    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;
        }

    }

According to ModelWrapper documentation:

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.

How to use such model classes, and not to implement the business logic twice (in the model class at the first time and in the ViewModel class at the second time)? Or maybe I have to move business-logic in other place?


Solution

  • The ModelWrapper is mainly intended for Java Bean classes without much logic. It's a helper to prevent users from having to write code to copy values from a model object to the ViewModel and back.

    In you example when you invoke the commit method of the ModelWrapper it will copy all values from the viewModel properties to the model instance by invoking all registered setter methods. This is done in the order in which the property fields are registered. If you have registered the intField-Property first, the ModelWrapper will first invoke the setIntField method (which changes intField and stringField in the model instance) and then invoke the setStringField method which overwrites the stringField. However, having to modify the order of field registration doesn't sound like a good idea and will most likely not scale for more complex model classes.

    So in the end I think the ModelWrapper is not a good tool for your use-case. In many cases there is no general answer on how to connect the model classes with the viewModel. It highly depends on the intended behavior and the use-cases.

    Regarding the question on the side-effect in the setter and if this is a code-smell: In my oppinion it's perfectly fine to modify the state of multiple internal fields with a single method. This is what OOP and information-hiding is all about. However, in Java there is the convention of getter and setter methods. If you name a method setIntField most Java developers will assume that this method only modifies intField and nothing more. So I would recommend to find a better name for such a method and keep getters and setters simple and straight forward.