Consider the following GUI screen:
When user selects a person from PersonListView
, EditPersonView
should show person's first name and last name and allow the user edit. So, I end up with the following UML class Diagram where each Java package represents the layer of the class.
My question is in SelectedPerson
and if this is an MVP "model" class. Should this be part of my application layer? Isn't a presentation concern? The reason I added there is so the 2 presenters can observe it. When user selected an element from the list widget, it gets updated and EditPersonViewPresenter
refreshes the 2 fields and "apply" button "Enability".
Class Persons
is another model, responsible for persons CRUD operations and it makes perfect sense to be part of the application layer (should it be in domain?). It is also responsible to notify its observers that a person had a CRUD operation on it. So, when "Apply" is pressed, PersonListViewPresenter
as an observer to Persons is capable to refresh the list and show the new first/last name in the list.
Long story short, the two presenters communicate through Persons
and SelectedPerson
models. Assume this is a "correct" approach.
Now, the devil comes.
Selection is available only when there are no unsaved changes in the EditPersonView
. If the person in record state is named "Jackie Chan" and user edits to "Hackie Chan", the selection is disabled until the user clicks apply or restores the fields to "Jackie" and "Chan".
How PersonListViewPresenter
can know whether there are unsaved changes in EditPersonView
?
According to the approach taken till now, a new model "EditPersonState" must be added in the application layer and follow the same approach. EditPersonViewPresenter
updates the EditPersonState
model and PersonListViewPresenter
observes it and operate accordingly (disable the selection in list). But, if I have X forms and multiple presenters are interesting in, I will have my application layer with X of such models (that exist only to synchronize presenters). Should it be that way?
On the other hand, the use case for example, is "User can delete the selected person" so having a SelectedPerson
model in application layer could allow me to put the Delete operation (of CRUD) there and make the use case(s) more "visible".
As an alternate solution I thought, I could let this state in the view. The view will be treated as "the view" and then keep a hierarchy of views and child views. Each presenter depend on "the view" (say MainView) and then observes any of the interesting (child)views. So SelectedPerson
model does not exist neither in application layer, neither in presenter layer. It exists in the child view. Persons
model remain (in app layer) to do the CRUD. Uml class Diagram of this approach:
But in this approach there is no one-to-one relationship between a view and a presenter. Not that is is a law, but maybe one day if I have 50 different views I won't be able to know which presenters touches which (proportion of a) view.
What am I missing?
Finally, one thought of mine stands in the following. Martin Fowler in the same page states the following:
Session State is data that the user is currently working on. Session state is seen by the user as somewhat temporary, they usually have the ability to save or discard their work.
So, based on that statement, the person selection is session state (?). According to Craig Larman in Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development there is the following figure:
If Larman's session state is the same thing as to Fowler's session state, then my current approach, SelectedPerson
in application layer agree with them.
Persons
is a service. A presenter gets the selected person and passes it toPersons
service. Notice how persons stand. It ispersons.delete(p)
notpersons.delete()
with association to selected person. I like the factPersons
stays as a (notifier) service with more business logic. Say I keep onlyPersons
, and selected person stays in presentation, howEditPersonViewPresenter
finds it in order topersons.update(selPerson)
?