MVC Exercise
Let’s build a quick program following the MVC architecture style to review working with classes, object, inheritance, and polymorphism.
Problem Statement
Write a program to store a list of students and teachers at a school. The program should have methods to add a student or a teacher, as well as a method to print the entire list.
UML Diagram
The program should conform to the following UML diagram:
Right-click and select “Open image in new tab” to view larger
The purpose of each method will be further described below.
Person
Class
__init__()
- constructor that initializes all attributes based on parameterslast_name()
- getter forlast_name
attribute—it should be implemented as a propertyget_first_name()
- getter forfirst_name
attribute—it should be implemented as a propertyget_age()
- getter forage
attribute—it should be implemented as a propertyhappy_birthday()
- method to increase person’sage
attribute by $1$__str__()
- method that overrides the built-inObject
class__str__()
method. It should return a string in the form"first_name last_name: age"
Student
Class
__init__()
- constructor that initializes all attributes (including in super class) based on parametersstudent_id()
- getter forstudent_id
attribute—it should be implemented as a propertygrade_level()
- getter forgrade_level
attribute—it should be implemented as a propertyhappy_birthday()
- method to increase student’sage
andgrade_level
attribute by $1$__str__()
- method that overrides the built-inObject
class__str__()
method. It should return a string in the form"first_name last_name: age (student_id - grade_level)"
Teacher
Class
__init__()
- constructor that initializes all attributes (including in super class) based on parametersclassroom()
- getter forclassroom
attribute—it should be implemented as a propertysalary()
- getter forsalary
attribute—it should be implemented as a propertyhappy_birthday()
- method to increase teacher’sage
by $1$ andsalary
attribute by $1000$__str__()
- method that overrides the built-inObject
class__str__()
method. It should return a string in the form"first_name last_name: age (classroom - $salary)"
View
Class
show_menu()
- a method to show a menu of options to the user. The user should be prompted to input exactly one of the options listed below, which is returned as a String. The wording of the menu is up to you. The method should return whatever was input by the user, without any error checking (that is done in the Controller)- “add student” - add a student
- “add teacher” - add a teacher
- “list people” - list the people
- “exit” - exit the program
add_student()
- a method to add a new student to the system. The user should input a list of parameters for each attribute as they are listed in the constructor forStudent
, separated by spaces. The wording of the prompt is up to you. The method should return whatever was input by the user, without any error checking (that is done in the Controller)- Example: “Smith John 25 123456 13”
add_teacher()
- a method to add a new teacher to the system. The user should input a list of parameters for each attribute as they are listed in the constructor forTeacher
, separated by spaces. The wording of the prompt is up to you. The method should return whatever was input by the user, without any error checking (that is done in the Controller)list_people()
- a method to list allPerson
objects in thepersons
list given as a parameter. Each one should be prefixed by an index starting at $0$, incrementing by one for eachPerson
in the list.- Example: “0) Smith John: 25 (geology - $1000)
show_error()
- a method to display an error to the user. The parametererror
should be printed to the screen, prefixed by “Error: "
Hint: use sys.stdin.readline()
to read an entire line of input anywhere in your code. Don’t forget to import sys
as well!
Controller
Class
main()
- the main method for this program. It should simply instantiate a new instance of the Controller class, and then call therun()
method of that object.__init__()
- the constructor for the Controller object. It initialize thepersons
attribute to an empty list, as well as aView
object stored in theview
attribute.run()
- this method consists of a loop that will execute the program until it is terminated. It will call theshowMenu()
method of the view to show a menu to the user (see above). Finally, it will parse the string returned by the call toshowMenu()
and call additional appropriate methods in theController
orView
class to complete the operation. If the user inputs “exit” then it should terminate. Otherwise, the program will repeatedly display the menu to the user until “exit” is chosen. If at any time the user provides input that cannot be properly parsed, the controller should call theshowError()
method in theView
class and restart the process (loop back to the beginning) by showing the menu again.add_student()
- this method will receive the string input by the user from theadd_student()
method inView
, parse the input, and call the appropriate methods to create a newStudent
object and add it to the first empty slot in thepersons
list.add_teacher()
- this method will receive the string input by the user from theadd_teacher()
method inView
, parse the input, and call the appropriate methods to create a newTeacher
object and add it to the first empty slot in thepersons
list.persons()
- these methods are a getter and setter for thepersons
attribute. They should be implemented as a property. It is for testing purposes only.
Sample Execution
A sample execution of the program is shown below.
Grading
Structure
{Check It!|assessment}(test-3416583454)
{Check It!|assessment}(test-1104470273)
{Check It!|assessment}(test-845982740)
{Check It!|assessment}(test-3746962485)
{Check It!|assessment}(test-3109390640)
Functionality
{Check It!|assessment}(test-1533527332)
{Check It!|assessment}(test-1355293558)
{Check It!|assessment}(test-3808852464)
{Check It!|assessment}(test-3597936585)
{Check It!|assessment}(test-1788523734)
Person
class Person:
def __init__(self, last_name, first_name, age):
self.__last_name = last_name
self.__first_name = first_name
self.__age = age
@property
def last_name(self):
return self.__last_name
@property
def first_name(self):
return self.__first_name
@property
def age(self):
return self.__age
def happy_birthday(self):
self.__age = self.__age + 1
def __str__(self):
return "{} {}: {}".format(self.first_name, self.last_name, self.age)
Student
from Person import Person
class Student(Person):
def __init__(self, last_name, first_name, age, student_id, grade_level):
super().__init__(last_name, first_name, age)
self.__student_id = student_id
self.__grade_level = grade_level
@property
def student_id(self):
return self.__student_id
@property
def grade_level(self):
return self.__grade_level
def happy_birthday(self):
super().happy_birthday()
self.__grade_level = self.__grade_level + 1
def __str__(self):
return "{} ({} - {})".format(super().__str__(), self.student_id, self.grade_level)
Teacher
from Person import Person
class Teacher(Person):
def __init__(self, last_name, first_name, age, classroom, salary):
super().__init__(last_name, first_name, age)
self.__classroom = classroom
self.__salary = salary
@property
def classroom(self):
return self.__classroom
@property
def salary(self):
return self.__salary
def __str__(self):
return "{} ({} - ${})".format(super().__str__(), self.classroom, self.salary)
View
import sys
class View:
def show_menu(self):
print("Please enter one of the following options:")
print(" add student")
print(" add teacher")
print(" list people")
print(" exit")
try:
inp = sys.stdin.readline()
return inp.strip()
except Exception:
return ""
def add_student(self):
print("Please enter the following items for the new student, all on the same line")
print("LastName FirstName Age StudentID GradeLevel")
try:
inp = sys.stdin.readline()
return inp.strip()
except Exception:
return ""
def add_teacher(self):
print("Please enter the following items for the new teacher, all on the same line")
print("LastName FirstName Age Classroom Salary")
try:
inp = sys.stdin.readline()
return inp.strip()
except Exception:
return ""
def list_people(self, persons):
i = 0
for p in persons:
print("{}) {}".format(i, p))
i += 1
def show_error(self, error):
print("Error: {}".format(error))
Controller
from Person import Person
from Student import Student
from Teacher import Teacher
from View import View
import sys
class Controller:
@staticmethod
def main(args):
Controller().run()
def __init__(self):
self.__persons = []
self.__view = View()
@property
def persons(self):
return self.__persons
@persons.setter
def persons(self, value):
self.__persons = value
def run(self):
while True:
inp = self.__view.show_menu()
if inp == "add student":
self.add_student(self.__view.add_student())
elif inp == "add teacher":
self.add_teacher(self.__view.add_teacher())
elif inp == "list people":
self.__view.list_people(self.__persons)
elif inp == "exit":
break
else:
self.__view.show_error("Invalid Input!")
def add_student(self, inp):
splits = inp.split(" ")
try:
p = Student(splits[0], splits[1], int(splits[2]), int(splits[3]), int(splits[4]))
self.__persons.append(p)
except Exception:
self.__view.show_error("Unable to parse input!")
def add_teacher(self, inp):
splits = inp.split(" ")
try:
p = Teacher(splits[0], splits[1], int(splits[2]), splits[3], int(splits[4]))
self.__persons.append(p)
except Exception:
self.__view.show_error("Unable to parse input!")
# main guard
if __name__ == "__main__":
Controller.main(sys.argv)