On 29/05/16 05:33, boB Stepp wrote:
> I am currently mulling over some information Alan passed along a while
> back on using the model-view-controller design pattern (Would
> 'architectural pattern' be a better choice of phrase?).  

Either is appropriate. Design Pattern is more usual, largely because
it ws one of the first OOP patterns to be formally documented (in
the SmalltTalk world) and is included in the original Design
Patterns book by the GoF.

> My current understanding is that the model contains program logic and
> the data which the program logic manipulates.  

Correct, all the core entities which make up the program are represented
by models. Most things stored in a database will
have a corresponding model.

> The view is just the interface with which the user interacts.  

Specifically the visible part of the interface. the "presentation layer".

> The controller ties things together, refreshing the view appropriately, 
> receiving messages from the view when something there has
> been changed by the user, interrogating the model when needed,
> and receiving the model's results and refreshing the view
> appropriately.

The controller is where the confusion starts. Every implementation of
the MVC pattern seems to change the way the controller is defined. You
are broadly correct but some frameworks have a more view focussed
interpretation, others more model focused. For example some GUI
frameworks combine the view and controller concepts into a single Window
object (the Delphi/VB/MFC/OWL Windows GUI frameworks all
take that approach). The JSP type 1 framework is similar in that
the JSP page does both roles. But in the JSP type 2 framework the
controller is separated out into a distinct entity.

What everybody(?!) seems to agree on is that events generated by the
view are forwarded to a controller(*) which determines whether a model
needs to be involved and is so what method of which model needs to
be invoked.

(*)If the controller is embedded in the view object then that is
probably handled by an internal  superclass method of the framework
and based on an event table (similar to Tkinter's binding mechanism)

The model responds, but how the view is notified varies. In some cases
the views register with models and the model automatically sends
notification messages to all registered views (by-passing the
controller). In other cases the model si8mply sends a reply to the
controller that invoked it and the controller decides which views should
be updated.

Thee is a modern twist on the whole thing too, where a View-Model is
introduced. This is a model object that represents an aggregated view of
lower level models and is closely aligned to the fields on a view.
(Think of it being like a view table in a SQL database, an aggregation
of multiple tables via a SELECT statement) In this case the controller
may simply update the view-model and the view model will notify its
associated view(s) directly. This is most commonly seen in the
Web/Javascript world where the browser holds a View-Model in memory
which is updated based on JSON queries back to the server which
hosts the real models. This architecture allows rich web clients
to do things like sorting or filtering the data without going back
to the server.

Another common use of a view-model is for collections. You may have many
foo objects (each one a model in its own right) but a list
view of them only wants a single model to work with so you create a
view-model representing the collection of foo. Each foo is persisted
in the database but the collection is a more abstract entity being in
effect the table as a whole.

> In my simple code to follow, I have the contents of three files, which
> I have named model.py, controller.py and view.py.  controller.py
> starts program execution.  My intent is to keep each of the three as
> independent of the others as I can manage, so that ideally, I could
> modify one of them and not need (or minimally need) to modify the
> other files.  

In practice it's hard to separate the controller and view
entirely (which is why some frameworks combine them) but
it should definitely be possible to separate the models
from the more UI elements. What the controller does do
is allow you to swap different views within a single UI.
For example a list view, versus a form view versus a
graphical view, all of the same object or set of objects.

> controller.py:

> def main():
>     '''Start and run the program.'''
> 
>     option_num = view.main_menu()
>     while True:
>         if option_num == '1':
>             diameter = float(view.diameter_prompt())
>             circumf = model.circumference(diameter)
>             view.display_circumference(str(diameter), str(circumf))
>             option_num = view.main_menu()
> 
>         elif option_num == '2':
>             view.display_exit_msg()
>             sys.exit()
> 
>         else:
>             title = 'WARNING!\n'
>             msg = ('That is not a valid option number.\nPlease enter a valid 
> ' +
>                     'number and press <Enter>.')
>             view.display_msg(title, msg)
>             option_num = view.main_menu()
> 
> if __name__ == '__main__':
>     main()
> ------------------------------------------------------------------------------------
> 
> model.py:
> 
> #!/usr/bin/env python3
> 
> '''Simple 'model' program to explore the model-view-controller design pattern.
> '''
> 
> import math
> 
> PI = math.pi
> 
> def circumference(diameter):
>     '''Calculate the circumference of a circle given its diameter.'''
> 
>     return PI * diameter
> ------------------------------------------------------------------------------------
> 
> view.py:
> 
> #!/usr/bin/env python3
> 
> '''Simple view program to explore the model-view-controller design pattern.'''
> 
> def main_menu():
>     '''Display main menu of options and return entered option number.'''
> 
>     print('''
>             Option 1:  Calculate the circumference of a circle.
>             Option 2:  Exit this program.
> 
>             ''')
>     main_menu_option = input('Enter an option number:  ')
>     return main_menu_option
> 
> def diameter_prompt():
>     '''Display a prompt to enter a diameter and return that value.'''
> 
>     print()
>     diameter = input('Enter a diameter:  ')
>     return diameter
> 
> def display_circumference(diameter, circumference):
>     '''Display the circumference calculated from the user-entered diameter.'''
> 
>     print()
>     print('You entered a diameter of', diameter, '.')
>     print('The circumference corresponding to that diameter is',
>             circumference, '.')
> 
> def display_exit_msg():
>     '''Display exiting the program message.'''
> 
>     print()
>     print('Exiting this program...\n')
> 
> def display_msg(title, msg):
>     '''Display the passed title and message.'''
> 
>     print()
>     print(title)
>     print(msg)
> ------------------------------------------------------------------------------------
> 
> Does my code capture the essence of MVC? 

For a CLI yes.

But I'd probably not make the controller the main() function.
Instead I'd have a separate main that constructed the objects.
The controller then has a handle_event() type method that
receives the event from the UI view.

So you make the view responsible for initiating the
event processing not the controller. The controller
then becomes a fairly simple validate-dispatch mechanism.

> anything or missing any nuances?  Would this code scale upward as I
> would hope?  

It would be a bit messy but could be adapted quite easily.
For example instead of the if/elif chain use a dictionary
for event dispatch.

> That is, if I chose to add more options as to what could
> be done with the program, would I only need to add only the code for
> the new functionality and not have to rewrite any existing code?  If I
> were to change from CLI to GUI, would this similarly mean only a
> rewrite of view.py without having to alter the other two files?

No because UI are event driven and have their own event loop.
That's why I'd move the main out of the controller. It's easier
to have the UI call your controller and just relay the event
info.

I gotta go so I'll get back to the other questions later if
nobody else has chimed in by then.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to