0

We have a set of domain objects that can be edited through in one window and used at the same time in other window. To ensure that the objects are in a valid state at all times and that changes are not visible to the outside world until they are committed. The objects are stored in a repository (each object has an unique id).

  1. User opens "Run" - window (read-only access to object A)
  2. User opens "Edit"-window (read/write access to object A)
  3. User changes some properties in the UI, but does not click apply
  4. User clicks the "Run"-button in the Run-window. The Run-operation should be performed with the "old" settings.
  5. User clicks the "Apply"-button in the Edit-window and Run in the Run-window. The Run-operation is performed with the "new" settings.

I can think of a few solutions, but I'm not very happy with either of them:

  1. When checking out objects from the repository, a clone is always returned. If one wish to store changes, the object must be explicitly committed to the repository. This could work well for small objects, but in cases where the object model is big it might not be plausible to clone everything.
  2. The view model or model stores intermediate changes and does not change the underlying domain object until the user decides that the changes should be applied. This sounds a bit tedious and will require a lot of validation rules in the view-models that we would rather like to have in the domain objects.
  3. The UI does not work directly on domain objects. Rather, they change DTOs that can be applied to the domain objects when the user applies the changes.

Note that there only will be one concurrent editor, but there might be multiple concurrent "readers". Also, concurrency won't be an issue (in the sense partially updated objects in a multi-threaded environment).

How can we implement a pattern for editing domain objects without applying changes until the changes are committed? Are there any frameworks I should look into?

larsmoa
  • 12,604
  • 8
  • 62
  • 85
  • I'd go to option 1 or 3 or a combination. Keep the least number of objects loaded by implementing lazy loading. – rro Nov 23 '12 at 08:21
  • Btw, you should implement and keep copies of the objects on individual user sessions – rro Nov 23 '12 at 08:34

1 Answers1

3

I think the Command pattern could be something that helps you here.
You basically would implement your Edit window to not directly work on the object but to create commands that change the object according to the data in the UI. Upon the click on Apply you execute those commands on the object, bringing it into the state the user chose.

Another approach would be to give the Edit and the Run window each their own instance and synchronize the object in the Run window "somehow" after the user clicked Apply. However, I am not quite sure how you would implement this without introducing a lot of coupling.

A third approach would be what I would implement:
As you are using MVVM, the edit Window and the Run window both have their own ViewModel instance. The ViewModel could hold an instance of the domain object. Both ViewModels would hold an instance to the same instance of the domain object.
Now, the ViewModel could be implemented in the following way:

  1. Its property getters return the value of the underlying domain object if no changes (see below) exist.
  2. When a property setter on the ViewModel is called, the value is not written to the domain object but to a corresponding field in the ViewModel. That's a change. From now on the ViewModel would return that value.
  3. The ViewModel has a method that writes the changes to the domain object. This method is not called automatically, it is to be called when the user clicks Apply in the Edit window.
  4. The ViewModel in the Run window will always return the data from the underlying domain object as it will never have changes.
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Thank you. Do you perform any state validation? I would like to ensure that the entered changes are valid, i.e. the domain object will remain valid when the changes are applied. Do you use any frameworks to handle the temporal changes? – larsmoa Nov 23 '12 at 08:47
  • 1
    @larsm: If you implement approach three, you can use Fluent Validation to validate the user input. – Daniel Hilgarth Nov 23 '12 at 08:52