The final design pattern is MVC - or the model-view-controller pattern. As you’ll see, it’s a great choice whenever a user has to interact frequently with the system you’re coding!
What Is MVC?
MVC is a software architecture approach. It divides the responsibilities of the system into three distinct parts:
Model: The model holds the state information of the system.
View: The view presents the model information to the user.
Controller: The controller makes sure that user commands are executed correctly, modifying the appropriate model objects, and updating the view objects.
How does this work in practice? Think about how you would interact with one of those old-school jukeboxes.
When you want to hear some tunes, all you’re concerned with is the tool for selecting songs and the speaker system that plays them to you.
You pay your coin, pick your chosen song, and finally listen to it while everyone within earshot judges you for your terrible taste in music. 😱
But you don’t care if the songs are in MP3 format, vinyl, or downloaded from the internet on the fly. You don’t care about how often the mechanic comes to service the machine and collects the money.
The things you interact with comprise the view, while behind the scenes, the model stores all of the state information, and the controller sequences all of the actions so that, for example, you can’t play your song before inserting your coin!
And it turns out it’s much simpler if these three components - with their separate responsibilities - are kept separate within the architecture of your system.
So how would this look if the jukebox were somehow implemented in Python?
What Goes in the Model (M)?
State information is kept in model classes. These are the items being viewed and manipulated. Also, if you need to store anything long term, it will be the model objects. For the jukebox, this might be the library of songs and artworks, the price list, and the date when the mechanic last visited.
PRICE_PER_SONG = 1.20
class Song:
def __init__(self, name, artist, genre, artwork):
self.artist = artist
self.name = name
self.genre = genre
self.artwork = artwork
class Library:
def __init__(self):
self.songs = []
class ServiceInfo:
def __init__(self, status, engineer_name):
self.service_date = datetime.now()
self.status = status
self.engineer = engineer_name
In the next chapter, you’ll practice applying this by developing a simple application, where you will put the relevant functionality in each of the model, view, and controller.
What Goes in the View (V)?
The view is how the model is presented and interacted with by the user. It's the most likely thing to change. You want the way this part interacts with the rest of the system to be distinct. For the jukebox, this would include the panel of buttons for selecting the music, the coin slot where you pay, and the speakers that blast out your favorite classics. 🎵
class Touchscreen:
def select_song(self):
pass
def prompt_for_next_song(self, songs):
for song in songs:
# display the songs
pass
return "Dark Chest of Wonders"
class Speakers:
def __init__(self):
self.volume = 5
def get_louder(self):
self.volume += 1
def get_quieter(self):
self.volume -= 1
def play_song(self, song):
pass
class CoinSlot:
def __init__(self, float_):
self.amount = float_
def request_money(self, amount):
# wait for money
# give change
self.amount += amount
return True
How can the view contain speakers? They don’t produce images!
True - but the view is just the general name given to all the system's user-facing components. The view will be the console output in our card game (next chapter), but it could instead be an API interface or a web page for other applications.
What Goes in the Controller (C)?
The controller is where the flow of the application is managed. All the sequencing of interactions between the user and the system is here. The user interacts with the view, which then interacts with the controller. The controller then makes the appropriate modifications to the model objects, makes new ones, or deletes no longer needed ones.
In the jukebox, this would include the logic that selects songs for you to browse, the logic that waits for you to pay before the music is played, and the system for calling the mechanic. Notice how the controller uses and modifies the model, and how it tells the view what to do.
class Controller:
def __init__(self):
self.library = Library()
self.service_history = []
self.audio_output = Speakers()
self.ui = Touchscreen()
self.bank = CoinBox()
def play_next_song(self):
songs_to_suggest = []
for song in self.library:
# filter logic
songs_to_suggest.append(song)
chosen_song = self.ui.prompt_for_next_song(songs_to_suggest)
request_money(PRICE_PER_SONG)
self.audio_output.play_song(chosen_song)
# Lots more functions go here...
What Are the Advantages of MVC?
Imagine you wanted to upgrade the old-school jukebox with the most exciting new music. You only need to update the model! The view and controller will work seamlessly with the updated library.
Or imagine you wanted to add some wireless headphones so you and your friends can go wild without disturbing the neighborhood. This only affects the view, while the model and controller stay untouched.
It also means you could test the headphone technology before buying and installing it by attaching it to another music device in the store!
Separating the parts of the architecture into different pieces with distinct responsibilities like this makes the system much easier to:
Modify
Test
Repair
Later in this course, you will learn the SOLID principles, which are rules you can follow to ensure your code is maintainable for these reasons. And no surprise - you’ll see that the MVC design pattern follows these principles very well!
Let’s Recap!
MVC ensures your code is easy to maintain by separating responsibilities:
The model contains state information.
The view contains the elements that interact with the user.
The controller makes sure the sequence of steps occurs correctly.
In the next chapter, we will concentrate on creating the model classes by creating a simple application together - a card game!