Model View Presenter GUI pattern?
Pedro
pedro_rodriguez at club-internet.fr
Fri Dec 14 18:44:12 EST 2001
In addition to others remarks (Chris, Patrick, Boudewijn,...),
I will suggest :
- if your observable class is supposed to be receiving different
notifications, an explicit way of dispatch them should be provided
otherwise your update method may turn in a suite of "if" to activate
the proper method, so :
def notify(self, eventName, *args, *kwargs):
for o in self.observers:
method = getattr(o, eventName)
method(*args, *kwargs)
- in my case, Chris remark doesn't hold as is because there is no more
update method, but still you will need to provide additionnal
concepts to ease development debugging to detect connecting mismatched
objects
1. an observable object should explicitly express which events
it will trigger, and their arguments
2. an observable should only trigger events it has expressed
3. an observer may be required to implement observable events
(1) is expressed in widget toolkits as callback prototypes (Gtk, Tk)
or signal concept (Qt, check Boudewijn Rempt documents on PyQt)
I suggest adding something like this :
class Observable:
class ObserverInterface: pass
...
def register(self, o):
if isinstance(o, self.ObserverInterface):
self.observers.append(o)
else:
raise Exception("%s does not implement %s"
% (o, self.ObserverInterface) )
...
def notify(self, eventName, *args, *kwargs):
if gettatr(self.ObserverInterface, eventName, None):
for o in self.observers:
method = getattr(o, eventName)
method(*args, *kwargs)
else:
raise Exception("%s does not emit %s" % (self, eventName))
So that an Observable class will look like:
class MyObservable(Observable):
def event1(x, y): pass
def event2(t, x, y, z): raise NotImplementedError
and an Observer for MyObservable class will look like :
class MyObserver(MyObservable.ObserverInterface):
def event1(...): ...
def event2(...): ...
This way you explicitly expose the interface of your Observable
class (1), you check that you don't generate invalid messages (2),
and you assert that an Observer for your Observable is meant to
be connected to it.
This is just a simplification. The check in the notification is
incomplete, it could be interesting to use inheritance in
ObserverInterface, this will require recursing in all __bases__
classes of self.ObserverInterface. Since this will be cost
effective at each notification, all event names should be store
in a dictionary at instance creation (and only once per class)
and events should be checked against it.
I wrote an application to experiment those kind of concepts, because
having started with a simple implementation of the Observer pattern,
I had some problems while developping (incorrect connections,
mispelled event names).
I also decided to check that the Observer prototype for an event
matches the one in ObserverInterface, to prevent things like :
def event1(x): ...
where
def event1(x,y): ...
(by prototype I mean here same number and name of arguments)
If you're interested I may put this application (another todo manager)
somewhere on the web (gtk, gnome, glade required).
> A few mvp references for the curious:
> http://www.object-arts.com/Lib/EducationCentre4/htm/modelviewpresenter.htm
> http://www.object-arts.com/EducationCentre/Overviews/ModelViewPresenter.htm
> http://www-106.ibm.com/developerworks/library/mvp.html
Thanks, for the links, since I try see what MVC and now MVP concepts
can do to improve my framework.
There are still things that bother me still, example :
- how do you deal with states of you application ?
For instance, some controllers/interactors should be disabled wether
you selected or unselected some item on list.
Presenter should be the ideal place to deal with it, but in
http://www-106.ibm.com/developerworks/library/mvp.html
they seem to put selection and interactors in different domains, not
to say on different machines
- should we force a Presenter to also be a View ?
--
Pedro
More information about the Python-list
mailing list