Boost logo

Boost :

From: Asger Alstrup Nielsen (alstrup_at_[hidden])
Date: 2000-11-30 05:29:45


> The view/controller needs three things from the model: 1)
> notfication of changes so that it can invalidate itself 2) access
> to the data so that it can render something for the user to see
> 3) mutators so that the user can change the model. Notification can
> be handled nicely via callbacks. I can imagine using some some sort
> of callback architecture to handle the other two but it's not a
> natural solution and it really seems like overkill when most views
> will never be reused in other contexts.

Just to illustrate the setup:

--Record.h:

class Record {
        ...
};

--Model.h:

#include "signal.h"
#include "record.h"
class Model {
public:
        signal<void, Record> sendUpdateToViews;
        void receiveUpdateFromView(Record r) {
                change model to reflect r
                sendUpdateToViews(r);
        }
};

--View.h

#include "signal.h"
#include "record.h"
class View {
public:
        signal<void, Record> sendUpdateToModel;
        void receiveUpdateFromModel(Record r) {
                updatescreen with r
        };

        // This is called when the view is changed
        void viewIsChanged(Record r) {
                sendUpdateToModel(r);
        }
}

--Controller.h:

#include "signal.h"
#include "View.h"
#include "Model.h"

class Controller {
public:
        void setup(Model & m, View & v) {
                connect(m.sendUpdateToViews, v, View::receiveUpdateFromModel);
                connect(v.sendUpdateToModel, m, Model::receiveUpdateFromView);
        }
}

--
That's all that it takes.
In effect, you have implemented the Observer design pattern twice:  The
Model is the subject for updating the observing views. The View is the
subject for making updates in the observing model.
This implementation of the Observer pattern is better than the
traditional, because you have done this with minimal coupling: The model
does not know about the view, and the view does not know about the
model. Instead both know about the Record, and the controller know about
the view and the model to make the connection.
It's also simpler because you can omit the normal abstract Model and
View classes in the standard Observer pattern implementation, which
normally serves to reduce coupling between concrete Model and View
classes.
Just to remind you:
The standard way of implementing the Observer pattern requires four
classes, plus optionally a controller for setup: An AbstractSubject and
an AbstractObserver. These define the interface for communication. Then
you need a ConcreteSubject which implements the AbstractSubject
interface, and a ConcreteObserver which implements the AbstractObserver.
Then, the AbstractSubject has to know about the AbstractObserver, and
that's the only coupling.
However, in the setup above with the proper signals, you can avoid even
this coupling. This in turn gives you the freedom to implement the other
direction in the Model/View separation: There is no harm in switching
roles such that the Model because the observer of View subjects.
This comes by a simpler setup than the normal Observer implementation,
and it's more flexible with less coupling.
All thanks to multi-casting lifetime-tolerant signals.
Greets,
Asger Alstrup Nielsen

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk