[Tutor] Correct use of model-view-controller design pattern

boB Stepp robertvstepp at gmail.com
Sun May 29 00:33:17 EDT 2016


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?).  I have been
doing my usual online readings and there is enough variation in what I
have read that I would like to post the simplest code I've been able
to come up with and see if my understanding of MVC is correct.

My current understanding is that the model contains program logic and
the data which the program logic manipulates.  The view is just the
interface with which the user interacts.  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.

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.  So, for instance, I would hope that I could change the
command line view code to a GUI and avoid having to change model.py at
all and hopefully have very few alterations to controller.py, though I
am not certain I can achieve the ideal of no modifications to the
controller.

Disclaimer:  While I tried to write my best Python possible, I did not
go full-bore and filter input, add error handling, except incidentally
in one else block.
------------------------------------------------------------------------------------

controller.py:

#!/usr/bin/env python3

'''Simple controller program to explore the model-view-controller
design pattern.'''

import sys

import model
import view

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?  Am I misunderstanding
anything or missing any nuances?  Would this code scale upward as I
would hope?  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?

Some other questions:

1)  If I were to add code to filter user inputs, which file is the
logical place to place such code?  My current impression is that it
should go in the controller, but I could see it being in the view.
However, if I were to write a Validation class, I could see that as
having uses beyond checking just user input.

2)  Currently I am using a while loop in the controller to keep the
view 'alive'.  If I were to convert the view to a tkinter GUI, where
would the root.mainloop() statement go?  In the controller's main()
method?  What GUI-related stumbling blocks might I easily run into in
going from CLI to GUI with this existing code?

3)  If I were to add data files in place of (or in addition to) user
input, in which aspect of MVC would file I/O be handled?

I also welcome any Python-style critiques, including even the more nit
picky ones. ~(:>)

BTW, I did not attempt to write any classes as things seemed simple
enough that functions seemed more appropriate and straightforward to
me.  If that is a bad choice, please let me know!

TIA!

-- 
boB


More information about the Tutor mailing list