MVC programming with python (newbie) - please help

Discussion in 'Python' started by bwaha, Jan 6, 2006.

  1. bwaha

    bwaha Guest

    I'd appreciate some experience from the gurus out there to help me
    understand how to implement MVC design in python code.

    Entry number 5 on the wxpython wiki at
    http://wiki.wxpython.org/index.cgi/BuildingControls discusses MVC design in
    building reusable controls. The author (Terrel Shumway) suggests that
    instead of:

    quote:

    class MyCoolListControl(...):
    def __init__(self,parent,id,choices):
    ...
    def InsertItem(...):
    def AppendItem(...):

    where choices is a static list, do something like this

    class ListDataModel:
    """ a minimal model interface to be used by MyCoolListControl """
    def __len__(self):
    """ return the number of items in the list """
    def __getitem__(self,index):
    """ return the specified item """

    # consider notifications for observers (e.g. the list control)

    # allow the user to define whatever mutators are appropriate


    class MyCoolListControl(...):
    def __init__(self,parent,id,model):
    ...
    def [GS]etModel(self,model):
    ...

    This allows the user (programmer) to store the data the way he thinks is
    best, rather than having to copy the data into your structure whenever it
    changes. It also reduces the need for kludges like [GS]etItemData for
    maintaining association of the real data with its currently displayed string
    representation.

    endquote

    The author refers to mvctree.py in wxPython as an example of MVC design.
    However I'm still too green so I find that particular example too complex
    and I'm not understanding the separation the author is recommending.

    Can anyone explain to me further the simple example above and/or supply a
    simple example of their own? At some level I feel like there's a benefit but
    I'm failing to grasp it, and how to implement it. If I understand correctly
    then in the future for example I could completely change how data is stored
    in the class ListDataModel and not require a change in class
    MyCoolListControl. Say, hypothetically, I wanted to implement ListDataModel
    using a dictionary rather than, more naturally, a list, where the "list"
    data structure is implemented as a dictionary and the list entries
    correspond to dictionary keys (dictionary values are not used in this case).
    Then if I understand the MVC concept, class MyCoolListControl need not
    change at all. If that's true then that's really cool. But I don't get how
    that works.

    I think I need a little further expansion of the example or an alternative
    (20-30 liner) that I can work through.

    The question arises in the context of wanting to build a dialog with a tree
    control that presents projects and studys as a tree and allows selection of
    projects and studies as required by the user. I want to parse a file with
    contents as follows:

    BEGIN PROJECT "mpi6_0"
    STUDY "Cyc0302_0" cyc0302_beanoz_x1.sdy
    STUDY "Cyc0305_0" cyc0305_beanoz_x1.sdy
    STUDY "Cyc0308_0" cyc0308_beanoz_x1.sdy
    STUDY "Cyc0311_0" cyc0311_beanoz_x1.sdy
    STUDY "Cyc0314_0" cyc0314_beanoz_x1.sdy
    END PROJECT
    BEGIN PROJECT "mpi6_1"
    STUDY "Cyc0302_1" cyc0302_beanoz_x1.sdy
    STUDY "Cyc0305_1" cyc0305_beanoz_x1.sdy
    STUDY "Cyc0308_1" cyc0308_beanoz_x1.sdy
    STUDY "Cyc0311_1" cyc0311_beanoz_x1.sdy
    STUDY "Cyc0314_1" cyc0314_beanoz_x1.sdy
    END PROJECT
    ....

    I have wriiten a class as follows that extracts the data from the file.

    import os

    class ProjectFileDecoder:
    """
    parse project file to obtain project names and associated studies and
    study files
    """
    def __init__(self, file):
    self.projects = {}
    self.parse_file(file)

    def parse_file(self, file):
    f = open(file, 'r')
    dir = os.path.split(file)
    while 1:
    line = f.readline()
    if 'BEGIN PROJECT' in line:
    proj_name = line.strip().split('"')[1]
    self.projects[proj_name] = {}
    elif 'STUDY' in line:
    study_name = (line.strip().split('"'))[1].strip()
    study_file = dir[0] + '/' +
    (line.strip().split('"'))[2].strip()
    self.projects[proj_name][study_name] = study_file
    elif not len(line):
    f.close()
    break

    def getProjectNames(self):
    return self.projects.keys()

    def getStudyNames(self):
    return [self.projects.keys() for i in self.getProjectNames()]

    def getStudyFiles(self):
    return [self.projects.values() for i in self.getProjectNames()]

    At some level this seems to me like the class ListDataModel above. I just
    need to make a MyTreeControl class. However here GS(et) routines are
    implemented in the ProjectFileDecoder class (data model?) whereas in the
    earlier advice they are in class MyCoolListControl. So I'm not understanding
    how data gets from the DataModel class to the ListControl class. After all
    the words I've said, I think that's the core misunderstanding I have.

    Hope someone can help clear that up for me.

    Chris
     
    bwaha, Jan 6, 2006
    #1
    1. Advertising

  2. bwaha wrote:

    > I'd appreciate some experience from the gurus out there to help me
    > understand how to implement MVC design in python code.
    >


    I'm neither a guru nor an expert, have never used wxpython, and am not
    qualified to advise on MVC!! But until someone more qualified arrives
    here's some code from a relative newbie.
    It's maybe not of any use in itself, but hopefully it won't lead you
    astray either.

    Hope it helps.

    Gerard




    ######## Model ########
    class Study(object):
    def __init__(self, name, file):
    self.name = name
    self.file = file

    class Project(object):
    def __init__(self, name):
    self.name = name
    self.studies = []
    ######## End Model ########

    ######## View ########
    class TreeViewNode(object):
    children = []
    tag = "NODE"

    class StudyNode(TreeViewNode):
    def __init__(self, study):
    self.tag = study.name
    self.file = study.file
    self.children = None

    class ProjectNode(TreeViewNode):
    def __init__(self, project):
    self.tag = project.name
    for study in project.studies:
    self.children.append( StudyNode(study) )

    class ProjectTreeView(TreeViewNode):
    def __init__(self):
    self.tag = "All Projects"

    def add_node(self, node):
    assert isinstance( node, ProjectNode )
    self.children.append(node)
    ######## End View ########

    data='''
    BEGIN PROJECT "mpi6_0"
    STUDY "Cyc0302_0" cyc0302_beanoz_x1.sdy
    STUDY "Cyc0305_0" cyc0305_beanoz_x1.sdy
    STUDY "Cyc0308_0" cyc0308_beanoz_x1.sdy
    STUDY "Cyc0311_0" cyc0311_beanoz_x1.sdy
    STUDY "Cyc0314_0" cyc0314_beanoz_x1.sdy
    END PROJECT
    BEGIN PROJECT "mpi6_1"
    STUDY "Cyc0302_1" cyc0302_beanoz_x1.sdy
    STUDY "Cyc0305_1" cyc0305_beanoz_x1.sdy
    STUDY "Cyc0308_1" cyc0308_beanoz_x1.sdy
    STUDY "Cyc0311_1" cyc0311_beanoz_x1.sdy
    STUDY "Cyc0314_1" cyc0314_beanoz_x1.sdy
    END PROJECT
    '''

    if __name__ == '__main__':
    import StringIO
    src = StringIO.StringIO(data)
    projects = []
    for line in src:
    parts = line.split(' ')
    begin = parts[0] == 'BEGIN'
    studyline = parts[0] == 'STUDY'
    end = parts[0] == 'END'
    if begin == True:
    project = Project( parts[2][1:-1] )
    elif studyline == True:
    project.studies.append( Study(parts[1][1:-1], parts[2]) )
    elif end == True:
    projects.append( project )

    for proj in projects:
    print 'PROJECT: ', proj.name
    for study in proj.studies:
    print '---- ', study.name

    MyTreeView = ProjectTreeView()
    for proj in projects:
    MyTreeView.add_node( ProjectNode(proj) )
    print MyTreeView
     
    Gerard Flanagan, Jan 6, 2006
    #2
    1. Advertising

  3. bwaha wrote:
    >
    > At some level this seems to me like the class ListDataModel above. I just
    > need to make a MyTreeControl class. However here GS(et) routines are
    > implemented in the ProjectFileDecoder class (data model?) whereas in the
    > earlier advice they are in class MyCoolListControl. So I'm not understanding
    > how data gets from the DataModel class to the ListControl class. After all
    > the words I've said, I think that's the core misunderstanding I have.
    >
    > Hope someone can help clear that up for me.


    You may want to look at the wxPython "virtual" ListCtrl (see the
    wxPython demo). Whenever a virtual ListCtrl is refreshed it will call
    specific methods on itself to get the appropriate content, e.g.
    OnGetItemText(self, rowIndex, columnIndex). You can do whatever you want
    in that method as long as you return the text that has to be displayed
    in the row with index rowIndex and the column with index columnIndex.
    One option would be to subclass wx.ListCtrl and provide something like
    your ListDataModel, like this (tested):

    import wx

    class MyCoolListControl(wx.ListCtrl):
    def __init__(self, *args, **kwargs):
    # don't pass the model argument to wx.ListCtrl:
    self._model = kwargs.pop('model')
    # force virtual mode:
    kwargs['style'] = wx.LC_VIRTUAL|kwargs['style']
    super(MyCoolListControl, self).__init__(*args, **kwargs)

    def OnGetItemText(self, rowIndex, columnIndex=0):
    return self._model.getItemText(rowIndex, columnIndex)

    # and similarly for OnGetItemImage and OnGetItemAttr


    class ListDataModel(object):
    def getItemText(self, rowIndex, columnIndex):
    return 'Text in row %d, column %d'%(rowIndex, columnIndex)


    app = wx.App(0)
    model = ListDataModel()
    window = wx.Frame(None)
    cool = MyCoolListControl(window, model=model, style=wx.LC_LIST)
    cool.SetItemCount(1000000) # This triggers a refresh of the list ctrl
    window.Show()
    app.MainLoop()



    In a similar vein you could use this scheme for wx.TreeCtrl, though that
    requires (much) more work because the TreeCtrl has no build-in virtual
    mode. That's what I did for the TreeListCtrl in Task Coach
    (http://taskcoach.niessink.com), see
    http://cvs.sourceforge.net/viewcvs..../taskcoachlib/widgets/treectrl.py?view=markup

    HTH, Frank
     
    Frank Niessink, Jan 6, 2006
    #3
  4. bwaha wrote:

    > I'd appreciate some experience from the gurus out there to help me
    > understand how to implement MVC design in python code.
    >



    ######## Model ########
    class Study(object):
    def __init__(self, name, file):
    self.name = name
    self.file = file

    class Project(object):
    def __init__(self, name):
    self.name = name
    self.studies = []
    ######## End Model ########

    data='''
    BEGIN PROJECT "mpi6_0"
    STUDY "Cyc0302_0" cyc0302_beanoz_x1.sdy
    STUDY "Cyc0305_0" cyc0305_beanoz_x1.sdy
    STUDY "Cyc0308_0" cyc0308_beanoz_x1.sdy
    STUDY "Cyc0311_0" cyc0311_beanoz_x1.sdy
    STUDY "Cyc0314_0" cyc0314_beanoz_x1.sdy
    END PROJECT
    BEGIN PROJECT "mpi6_1"
    STUDY "Cyc0302_1" cyc0302_beanoz_x1.sdy
    STUDY "Cyc0305_1" cyc0305_beanoz_x1.sdy
    STUDY "Cyc0308_1" cyc0308_beanoz_x1.sdy
    STUDY "Cyc0311_1" cyc0311_beanoz_x1.sdy
    STUDY "Cyc0314_1" cyc0314_beanoz_x1.sdy
    END PROJECT
    '''

    if __name__ == '__main__':
    import StringIO
    src = StringIO.StringIO(data)
    projects = []
    for line in src:
    parts = line.split(' ')
    begin = parts[0] == 'BEGIN'
    studyline = parts[0] == 'STUDY'
    end = parts[0] == 'END'
    if begin == True:
    project = Project( parts[2][1:-1] )
    elif studyline == True:
    project.studies.append( Study(parts[1][1:-1], parts[2]) )
    elif end == True:
    projects.append( project )

    for proj in projects:
    print 'PROJECT: ', proj.name
    for study in proj.studies:
    print '---- ', study.name
     
    Gerard Flanagan, Jan 6, 2006
    #4
  5. Gerard Flanagan wrote:

    > bwaha wrote:
    >
    > > I'd appreciate some experience from the gurus out there to help me
    > > understand how to implement MVC design in python code.
    > >

    >


    Badly snipped, not pretending to be a 'guru'....


    Gerard
     
    Gerard Flanagan, Jan 6, 2006
    #5
  6. bwaha

    has Guest

    bwaha wrote:
    > The author refers to mvctree.py in wxPython as an example of MVC design.
    > However I'm still too green so I find that particular example too complex
    > and I'm not understanding the separation the author is recommending.


    MVC is all about separation of concerns.

    The Model is responsible for managing the program's data (both private
    and client data). The View/Controller is responsible for providing the
    outside world with the means to interact with the program's client
    data.

    The Model provides an internal interface (API) to enable other parts of
    the program to interact with it. The View/Controller provides an
    external interface (GUI/CLI/web form/high-level IPC/etc.) to enable
    everything outwith the program to communicate with it.

    The Model is responsible for maintaining the integrity of the program's
    data, because if that gets corrupted then it's game over for everyone.
    The View/Controller is responsible for maintaining the integrity of the
    UI, making sure all text views are displaying up-to-date values,
    disabling menu items that don't apply to the current focus, etc.

    The Model contains no View/Controller code; no GUI widget classes, no
    code for laying out dialog boxes or receiving user input. The
    View/Controller contains no Model code; no code for validating URLs or
    performing SQL queries, and no original state either: any data held by
    widgets is for display purposes only, and merely a reflection of the
    true data stored in the Model.


    Now, here's the test of a true MVC design: the program should in
    essence be fully functional even without a View/Controller attached.
    OK, the outside world will have trouble interacting with it in that
    form, but as long as one knows the appropriate Model API incantations,
    the program will hold and manipulate data as normal.

    Why is this possible? Well, the simple answer is that it's all thanks
    to the low coupling between the Model and View/Controller layers.
    However, this isn't the full story. What's key to the whole MVC pattern
    is the _direction_ in which those connection goes: ALL instructions
    flow _from_ the View/Controller _to_ the Model. The Model NEVER tells
    the View/Controller what to do.

    Why? Because in MVC, while the View/Controller is permitted to know a
    little about the Model (specifically, the Model's API), but the Model
    is not allowed to know anything whatsoever about the View/Controller.

    Why? Because MVC is about creating a clear separation of concerns.

    Why? To help prevent program complexity spiralling out of control and
    burying you, the developer, under it. The bigger the program, the
    greater the number of components in that program. And the more
    connections exist between those components, the harder it is for
    developers to maintain/extend/replace individual components, or even
    just follow how the whole system works. Ask yourself this: when looking
    at a diagram of the program's structure, would you rather see a tree or
    a cat's cradle? The MVC pattern avoids the latter by disallowing
    circular connections: B can connect to A, but A cannot connect to B. In
    this case, A is the Model and B is the View/Controller.

    BTW, if you're sharp, you'll notice a problem with the 'one-way'
    restriction just described: how can the Model inform the
    View/Controller of changes in the Model's user data when the Model
    isn't even allowed to know that the View/Controller, never mind send
    messages to it? But don't worry: there is a solution to this, and it's
    rather neat even if it does seem a bit roundabout at first. We'll get
    back to that in a moment.


    In practical terms, then, a View/Controller object may, via the Model's
    API, 1. tell the Model to do things (execute commands), and 2. tell the
    Model to give it things (return data). The View/Controller layer
    *pushes instructions* to the Model layer and *pulls information* from
    the Model layer.

    And that's where your first MyCoolListControl example goes wrong,
    because the API for that class requires that information be *pushed*
    into it, so you're back to having a two-way coupling between layers,
    violating the MVC rules and dumping you right back into the cat's
    cradle architecture that you were [presumably] trying to avoid in the
    first place.

    Instead, the MyCoolListControl class should go with the flow, pulling
    the data it needs from the layer below, when it needs it. In the case
    of a list widget, that generally means asking how many values there are
    and then asking for each of those items in turn, because that's about
    the simplest and loosest way to do it and therefore keeps what coupling
    there is to a minimum. And if the widget wants, say, to present those
    values to the user in nice alphabetical order then that's its
    perogative; and its responsibility, of course.


    Now, one last conundrum, as I hinted at earlier: how do you keep the
    UI's display synchronised with the Model's state in an MVC-based
    system?

    Here's the problem: many View objects are stateful, e.g. a checkbox may
    be ticked or unticked, a text field may contain some editable text.
    However, MVC dictates that all user data be stored in the Model layer,
    so any data held by other layers for display purposes (the checkbox's
    state, the text field's current text) must therefore be a subsidiary
    copy of that primary Model data. But if the Model's state changes, the
    View's copy of that state will no longer be accurate and needs to be
    refreshed.

    But how? The MVC pattern prevents the Model pushing a fresh copy of
    that information into the View layer. Heck, it doesn't even allow the
    Model to send the View a message to say its state has changed.

    Well, almost. Okay, the Model layer isn't allowed to talk directly to
    other layers, since to do so would require it knows something about
    those layers, and MVC rules prevent that. However, if a tree falls in a
    forest and nobody's around to hear it, does it make a sound?

    The answer, you see, is to set up a notifications system, providing the
    Model layer with a place it can announce to no-one in particular that
    it has just done something interesting. Other layers can then post
    listeners with that notification system to listen for those
    announcements that they're actually interested in. The Model layer
    doesn't need to know anything about who's listening (or even if anyone
    is listening at all!); it just posts an announcement and then forgets
    about it. And if anyone hears that announcement and feels like doing
    something afterwards - like asking the Model for some new data so it
    can update its on-screen display - then great. The Model just lists
    what notifications it sends as part of its API definition; and what
    anyone else does with that knowledge is up to them.

    MVC is preserved, and everyone is happy. Your application framework may
    well provide a built-in notifications system, or you can write your own
    if not (see the 'observer pattern').

    ....

    Anyway, hope that helps. Once you understand the motivations behind
    MVC, the reasons why things are done the way they are starts to make
    sense, even when - at first glance - they seem more complex than
    necessary.

    Cheers,

    has
     
    has, Jan 7, 2006
    #6
  7. bwaha

    bwaha Guest

    "Gerard Flanagan" <> wrote in message
    news:...
    > Gerard Flanagan wrote:
    >
    > > bwaha wrote:
    > >
    > > > I'd appreciate some experience from the gurus out there to help me
    > > > understand how to implement MVC design in python code.
    > > >

    > >

    >
    > Badly snipped, not pretending to be a 'guru'....
    >
    >
    > Gerard
    >


    You taught me something so in in some part at least you are. Thanks.
     
    bwaha, Jan 8, 2006
    #7
  8. bwaha

    bwaha Guest

    "bwaha" <> wrote in message
    news:O5uvf.199294$...
    > I'd appreciate some experience from the gurus out there to help me
    > understand how to implement MVC design in python code.


    <snip>

    Thanks for all the help. Also this link was sent to me by pm and I found
    this very useful too. Its a short wxpython MVC exmaple. (Thanks. Sanchit).

    http://www.techietwo.com/detail-6332577.html
     
    bwaha, Jan 8, 2006
    #8
  9. bwaha

    has Guest

    bwaha wrote:
    > The author refers to mvctree.py in wxPython as an example of MVC design.
    > However I'm still too green so I find that particular example too complex
    > and I'm not understanding the separation the author is recommending.


    MVC is all about separation of concerns.

    The Model is responsible for managing the program's data (both private
    and client data). The View/Controller is responsible for providing the
    outside world with the means to interact with the program's client
    data.

    The Model provides an internal interface (API) to enable other parts of
    the program to interact with it. The View/Controller provides an
    external interface (GUI/CLI/web form/high-level IPC/etc.) to enable
    everything outwith the program to communicate with it.

    The Model is responsible for maintaining the integrity of the program's
    data, because if that gets corrupted then it's game over for everyone.
    The View/Controller is responsible for maintaining the integrity of the
    UI, making sure all text views are displaying up-to-date values,
    disabling menu items that don't apply to the current focus, etc.

    The Model contains no View/Controller code; no GUI widget classes, no
    code for laying out dialog boxes or receiving user input. The
    View/Controller contains no Model code; no code for validating URLs or
    performing SQL queries, and no original state either: any data held by
    widgets is for display purposes only, and merely a reflection of the
    true data stored in the Model.


    Now, here's the test of a true MVC design: the program should in
    essence be fully functional even without a View/Controller attached.
    OK, the outside world will have trouble interacting with it in that
    form, but as long as one knows the appropriate Model API incantations,
    the program will hold and manipulate data as normal.

    Why is this possible? Well, the simple answer is that it's all thanks
    to the low coupling between the Model and View/Controller layers.
    However, this isn't the full story. What's key to the whole MVC pattern
    is the _direction_ in which those connection goes: ALL instructions
    flow _from_ the View/Controller _to_ the Model. The Model NEVER tells
    the View/Controller what to do.

    Why? Because in MVC, while the View/Controller is permitted to know a
    little about the Model (specifically, the Model's API), but the Model
    is not allowed to know anything whatsoever about the View/Controller.

    Why? Because MVC is about creating a clear separation of concerns.

    Why? To help prevent program complexity spiralling out of control and
    burying you, the developer, under it. The bigger the program, the
    greater the number of components in that program. And the more
    connections exist between those components, the harder it is for
    developers to maintain/extend/replace individual components, or even
    just follow how the whole system works. Ask yourself this: when looking
    at a diagram of the program's structure, would you rather see a tree or
    a cat's cradle? The MVC pattern avoids the latter by disallowing
    circular connections: B can connect to A, but A cannot connect to B. In
    this case, A is the Model and B is the View/Controller.

    BTW, if you're sharp, you'll notice a problem with the 'one-way'
    restriction just described: how can the Model inform the
    View/Controller of changes in the Model's user data when the Model
    isn't even allowed to know that the View/Controller, never mind send
    messages to it? But don't worry: there is a solution to this, and it's
    rather neat even if it does seem a bit roundabout at first. We'll get
    back to that in a moment.


    In practical terms, then, a View/Controller object may, via the Model's
    API, 1. tell the Model to do things (execute commands), and 2. tell the
    Model to give it things (return data). The View/Controller layer
    *pushes instructions* to the Model layer and *pulls information* from
    the Model layer.

    And that's where your first MyCoolListControl example goes wrong,
    because the API for that class requires that information be *pushed*
    into it, so you're back to having a two-way coupling between layers,
    violating the MVC rules and dumping you right back into the cat's
    cradle architecture that you were [presumably] trying to avoid in the
    first place.

    Instead, the MyCoolListControl class should go with the flow, pulling
    the data it needs from the layer below, when it needs it. In the case
    of a list widget, that generally means asking how many values there are
    and then asking for each of those items in turn, because that's about
    the simplest and loosest way to do it and therefore keeps what coupling
    there is to a minimum. And if the widget wants, say, to present those
    values to the user in nice alphabetical order then that's its
    perogative; and its responsibility, of course.


    Now, one last conundrum, as I hinted at earlier: how do you keep the
    UI's display synchronised with the Model's state in an MVC-based
    system?

    Here's the problem: many View objects are stateful, e.g. a checkbox may
    be ticked or unticked, a text field may contain some editable text.
    However, MVC dictates that all user data be stored in the Model layer,
    so any data held by other layers for display purposes (the checkbox's
    state, the text field's current text) must therefore be a subsidiary
    copy of that primary Model data. But if the Model's state changes, the
    View's copy of that state will no longer be accurate and needs to be
    refreshed.

    But how? The MVC pattern prevents the Model pushing a fresh copy of
    that information into the View layer. Heck, it doesn't even allow the
    Model to send the View a message to say its state has changed.

    Well, almost. Okay, the Model layer isn't allowed to talk directly to
    other layers, since to do so would require it knows something about
    those layers, and MVC rules prevent that. However, if a tree falls in a
    forest and nobody's around to hear it, does it make a sound?

    The answer, you see, is to set up a notifications system, providing the
    Model layer with a place it can announce to no-one in particular that
    it has just done something interesting. Other layers can then post
    listeners with that notification system to listen for those
    announcements that they're actually interested in. The Model layer
    doesn't need to know anything about who's listening (or even if anyone
    is listening at all!); it just posts an announcement and then forgets
    about it. And if anyone hears that announcement and feels like doing
    something afterwards - like asking the Model for some new data so it
    can update its on-screen display - then great. The Model just lists
    what notifications it sends as part of its API definition; and what
    anyone else does with that knowledge is up to them.

    MVC is preserved, and everyone is happy. Your application framework may
    well provide a built-in notifications system, or you can write your own
    if not (see the 'observer pattern').

    ....

    Anyway, hope that helps. Once you understand the motivations behind
    MVC, the reasons why things are done the way they are starts to make
    sense, even when - at first glance - they seem more complex than
    necessary.

    Cheers,

    has
     
    has, Jan 8, 2006
    #9
  10. has wrote:
    > MVC is all about separation of concerns....

    This is a wonderful explanation of MVC. I'm going to keep a link to the
    Google-Groups version just so I can cite it to those asking about MVC.

    --Scott David Daniels
     
    Scott David Daniels, Jan 8, 2006
    #10
  11. bwaha

    has Guest

    bwaha wrote:
    > The author refers to mvctree.py in wxPython as an example of MVC design.
    > However I'm still too green so I find that particular example too complex
    > and I'm not understanding the separation the author is recommending.


    MVC is all about separation of concerns.

    The Model is responsible for managing the program's data (both private
    and client data). The View/Controller is responsible for providing the
    outside world with the means to interact with the program's client
    data.

    The Model provides an internal interface (API) to enable other parts of
    the program to interact with it. The View/Controller provides an
    external interface (GUI/CLI/web form/high-level IPC/etc.) to enable
    everything outwith the program to communicate with it.

    The Model is responsible for maintaining the integrity of the program's
    data, because if that gets corrupted then it's game over for everyone.
    The View/Controller is responsible for maintaining the integrity of the
    UI, making sure all text views are displaying up-to-date values,
    disabling menu items that don't apply to the current focus, etc.

    The Model contains no View/Controller code; no GUI widget classes, no
    code for laying out dialog boxes or receiving user input. The
    View/Controller contains no Model code; no code for validating URLs or
    performing SQL queries, and no original state either: any data held by
    widgets is for display purposes only, and merely a reflection of the
    true data stored in the Model.


    Now, here's the test of a true MVC design: the program should in
    essence be fully functional even without a View/Controller attached.
    OK, the outside world will have trouble interacting with it in that
    form, but as long as one knows the appropriate Model API incantations,
    the program will hold and manipulate data as normal.

    Why is this possible? Well, the simple answer is that it's all thanks
    to the low coupling between the Model and View/Controller layers.
    However, this isn't the full story. What's key to the whole MVC pattern
    is the _direction_ in which those connection goes: ALL instructions
    flow _from_ the View/Controller _to_ the Model. The Model NEVER tells
    the View/Controller what to do.

    Why? Because in MVC, while the View/Controller is permitted to know a
    little about the Model (specifically, the Model's API), but the Model
    is not allowed to know anything whatsoever about the View/Controller.

    Why? Because MVC is about creating a clear separation of concerns.

    Why? To help prevent program complexity spiralling out of control and
    burying you, the developer, under it. The bigger the program, the
    greater the number of components in that program. And the more
    connections exist between those components, the harder it is for
    developers to maintain/extend/replace individual components, or even
    just follow how the whole system works. Ask yourself this: when looking
    at a diagram of the program's structure, would you rather see a tree or
    a cat's cradle? The MVC pattern avoids the latter by disallowing
    circular connections: B can connect to A, but A cannot connect to B. In
    this case, A is the Model and B is the View/Controller.

    BTW, if you're sharp, you'll notice a problem with the 'one-way'
    restriction just described: how can the Model inform the
    View/Controller of changes in the Model's user data when the Model
    isn't even allowed to know that the View/Controller, never mind send
    messages to it? But don't worry: there is a solution to this, and it's
    rather neat even if it does seem a bit roundabout at first. We'll get
    back to that in a moment.


    In practical terms, then, a View/Controller object may, via the Model's
    API, 1. tell the Model to do things (execute commands), and 2. tell the
    Model to give it things (return data). The View/Controller layer
    *pushes instructions* to the Model layer and *pulls information* from
    the Model layer.

    And that's where your first MyCoolListControl example goes wrong,
    because the API for that class requires that information be *pushed*
    into it, so you're back to having a two-way coupling between layers,
    violating the MVC rules and dumping you right back into the cat's
    cradle architecture that you were [presumably] trying to avoid in the
    first place.

    Instead, the MyCoolListControl class should go with the flow, pulling
    the data it needs from the layer below, when it needs it. In the case
    of a list widget, that generally means asking how many values there are
    and then asking for each of those items in turn, because that's about
    the simplest and loosest way to do it and therefore keeps what coupling
    there is to a minimum. And if the widget wants, say, to present those
    values to the user in nice alphabetical order then that's its
    perogative; and its responsibility, of course.


    Now, one last conundrum, as I hinted at earlier: how do you keep the
    UI's display synchronised with the Model's state in an MVC-based
    system?

    Here's the problem: many View objects are stateful, e.g. a checkbox may
    be ticked or unticked, a text field may contain some editable text.
    However, MVC dictates that all user data be stored in the Model layer,
    so any data held by other layers for display purposes (the checkbox's
    state, the text field's current text) must therefore be a subsidiary
    copy of that primary Model data. But if the Model's state changes, the
    View's copy of that state will no longer be accurate and needs to be
    refreshed.

    But how? The MVC pattern prevents the Model pushing a fresh copy of
    that information into the View layer. Heck, it doesn't even allow the
    Model to send the View a message to say its state has changed.

    Well, almost. Okay, the Model layer isn't allowed to talk directly to
    other layers, since to do so would require it knows something about
    those layers, and MVC rules prevent that. However, if a tree falls in a
    forest and nobody's around to hear it, does it make a sound?

    The answer, you see, is to set up a notifications system, providing the
    Model layer with a place it can announce to no-one in particular that
    it has just done something interesting. Other layers can then post
    listeners with that notification system to listen for those
    announcements that they're actually interested in. The Model layer
    doesn't need to know anything about who's listening (or even if anyone
    is listening at all!); it just posts an announcement and then forgets
    about it. And if anyone hears that announcement and feels like doing
    something afterwards - like asking the Model for some new data so it
    can update its on-screen display - then great. The Model just lists
    what notifications it sends as part of its API definition; and what
    anyone else does with that knowledge is up to them.

    MVC is preserved, and everyone is happy. Your application framework may
    well provide a built-in notifications system, or you can write your own
    if not (see the 'observer pattern').

    ....

    Anyway, hope that helps. Once you understand the motivations behind
    MVC, the reasons why things are done the way they are starts to make
    sense, even when - at first glance - they seem more complex than
    necessary.

    Cheers,

    has
     
    has, Jan 8, 2006
    #11
  12. bwaha

    bwaha Guest

    "has" <> wrote in message
    news:...
    > bwaha wrote:
    > > The author refers to mvctree.py in wxPython as an example of MVC design.
    > > However I'm still too green so I find that particular example too

    complex
    > > and I'm not understanding the separation the author is recommending.

    >
    > MVC is all about separation of concerns.
    >


    <snip>

    Woh!!! A disertation (x3). Very much appreciated. It will take much more a
    single reading but I'm sure it will help me understand the samples supplied
    by the earlier posters. Thanks.
     
    bwaha, Jan 9, 2006
    #12
  13. bwaha

    bwaha Guest

    <snip>

    Well I read this in daylight hours. Talk about Enlightening!!!. It all
    became clear. Now I even understand the point of an observer class, which
    was shown in an example I posted back to the group from an earlier reply.

    Thanks again for sharing your knowledge.

    Be Well and Happy Always

    Chris
     
    bwaha, Jan 11, 2006
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. KK
    Replies:
    2
    Views:
    728
    Big Brian
    Oct 14, 2003
  2. rmn190
    Replies:
    2
    Views:
    2,475
    Arne Vajhøj
    Jan 10, 2008
  3. Paulo
    Replies:
    3
    Views:
    511
    Peter Bromberg [C# MVP]
    Dec 4, 2008
  4. Crazy Cat
    Replies:
    1
    Views:
    725
    schepp
    Sep 3, 2009
  5. Fritjolf
    Replies:
    0
    Views:
    1,036
    Fritjolf
    Jan 14, 2011
Loading...

Share This Page