Background
We use the Model-View-Presenter design pattern along with the abstract factory pattern and the "signal/slot" pattern in our application, to fullfill 2 main requirements
- Enhance testability (very lightweight GUI, every action can be simulated in unit tests)
- Make the "view" totally independant from the rest, so we can change the actual view implementation, without changing anything else
In order to do so our code is divided in 4 layers :
- Core : which holds the model
- Presenter : which manages interactions between the view interfaces (see bellow) and the core
- View Interfaces : they define the signals and slots for a View, but not the implementation
- Views : the actual implementation of the views
When the presenter creates or deals with views, it uses an abstract factory and only knows about the view interfaces.
It does the signal/slot binding between views interfaces. It doesn't care about the actual implementation. In the "views" layer, we have a concrete factory which deals with implementations.
The signal/slot mechanism is implemented using a custom framework built upon boost::function.
Really, what we have is something like that : http://martinfowler.com/eaaDev/PassiveScreen.html
Everything works fine.
The problem
However, there's a problem I don't know how to solve.
Let's take for example a very simple drag and drop example.
I have two ContainersViews (ContainerView1, ContainerView2). ContainerView1 has an ItemView1. I drag the ItemView1 from ContainerView1 to ContainerView2.
ContainerView2 must create an ItemView2, of a different type, but which "points" to the same model object as ItemView1.
So the ContainerView2 gets a callback called for the drop action with ItemView1 as a parameter. It calls ContainerPresenterB passing it ItemViewB
In this case we are only dealing with views. In MVP-PV, views aren't supposed to know anything about the presenter nor the model, right ?
How can I create the ItemView2 from the ItemView1, not knowing which model object is ItemView1 representing ?
I thought about adding an "itemId" to every view, this id being the id of the core object the view represents.
So in pseudo code, ContainerPresenter2 would do something like
itemView2=abstractWidgetFactory.createItemView2();
this.add(itemView2,itemView1.getCoreObjectId())
I don't get too much into details. That just work. The problem I have here is that those itemIds are just like pointers. And pointers can be dangling. Imagine that by mistake, I delete itemView1, and this deletes coreObject1. The itemView2 will have a coreObjectId which represents an invalid coreObject.
Isn't there a more elegant and "bulletproof" solution ?
Even though I never did ObjectiveC or macOSX programming, I couldn't help but notice that our framework is very similar to Cocoa framework. How do they deal with this kind of problem ? Couldn't find more in-depth information about that on google. If someone could shed some light on this.
I hope this question isn't too confusing ...