C++ – a good strategy for binding view objects to model objects in C++

cmvc

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?

Best Answer

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.

Related Topic