Model View Presenter GUI pattern?

Pedro pedro_rodriguez at club-internet.fr
Sat Dec 15 00:44:12 CET 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