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.
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 ...