|
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