6

Imagine I have a rich data model that is represented by a hierarchy of objects.

I also have a view hierarchy with views that can extract required data from model objects and display the data (and allow the user to manipulate the data).

Actually, there could be multiple view hierarchies that can represent and manipulate the model (e.g. an overview-detail view and a direct manipulation view).

My current approach for this is for the controller layer to store a reference to the underlying model object in the View object. The view object can then get the current data from the model for display, and can send the model object messages to update the data. View objects are effectively observers of the model objects and the model objects broadcast notifications when properties change.

This approach allows all the views to update simultaneously when any view changes the model.

Implemented carefully, this all works. However, it does require a lot of work to ensure that no view or model objects hold any stale references to model objects. The user can delete model objects or sub-hierarchies of the model at any time. Ensuring that all the view objects that hold references to the model objects that have been deleted is time-consuming and difficult.

It feels like the approach I have been taking is not especially clean; while I don't want to have to have explicit code in the controller layer for mediating the communication between the views and the model, it seems like there must be a better (implicit) approach for establishing bindings between the view and the model and between related model objects.

In particular, I am looking for an approach (in C++) that understands two key points:

  1. There is a many to one relationship between view and model objects
  2. If the underlying model object is destroyed, all the dependent view objects must be cleaned up so that no stale references exist

While shared_ptr and weak_ptr can be used to manage the lifetimes of the underlying model objects and allows for weak references from the view to the model, they don't provide for notification of the destruction of the underlying object (they do in the sense that the use of a stale weak_ptr allows for notification), but I need an approach that notifies the dependent objects that their weak reference is going away.

Can anyone suggest a good strategy to manage this?

1
  • A combination of something like boost::signals2 and shared_ptr may do the trick...
    – Guy Sirton
    Commented Jul 26, 2013 at 5:25

3 Answers 3

3

Be aware that you're accurately describing the observer design pattern, given the domain model object to be the subject and the views to be observers. Note also that the observer pattern implies a higher level of abstraction than a smart pointer, and that there is no direct conceptual correspondence between the two of them.

In order to implement this pattern, you must firstly ensure that all the involved views (observers) implement a common interface, for example by inheriting a common base, abstract class. Then, the domain object (subject) can proceed with managing a set of references to instances of that said observer interface, and notifying them all when required, by calling the appropriate interface methods.

Smart pointers can be used in this scheme to implement the references managed by the subject.

0

Well, you can always create your own smart pointer that will notify the referrers. It's not that difficult.

The weak pointers don't have notification because it would require list of weak references that exist and that would in turn require nontrivial synchronization in multi-threaded environment while the implementation without it takes just an extra level of indirection. But especially if you have some constraints from which threads the models can be deleted (GUI frameworks are usually single-threaded anyway), it's possible.

2
  • Thanks Jan. This seems more like a tactic than a strategy. It may well make things better, but it still seems like the approach means that the Views have too much information about the model. Are there any examples of a strategy to solve this sort of problem that allows for the proper layering; maybe some mechanism for generic bindings in the controller?
    – B.J.
    Commented Jul 26, 2013 at 19:51
  • @B.J.: Generic bindings is a matter of generalizing the interface to the objects that the view is looking at and the notifications that something went away. Under the hood, the references will still be kind of notified weak pointers.
    – Jan Hudec
    Commented Jul 29, 2013 at 9:50
0

If I understand your design correctly, you have a model-view model.

To improve it, you can use MVC design with observer pattern, where :

  • controllers are just connecting models->views and views->models signals to slots
  • views are showing what they need to show, listen to relevant events from the model in order to update the view, and forwards the user's interaction to models
  • models are implementing the logic. They handle user's interaction, and sends events to views to inform them of changes

This way, if you wish to destroy a model, you can do it without much hastle. You will also have to break connections in the controller.

Here you can see how I implemented MVC in qt5. It may evolve into something useful in far future, but for now it is just for demonstration purposes :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.