Skip to content

Latest commit

 

History

History
127 lines (102 loc) · 4.67 KB

File metadata and controls

127 lines (102 loc) · 4.67 KB

Traditional MVC

With the Document-View design we successfully extracted state from an initial Smart-UI design. The next objective is to extract the code that converts the primary event (in this case, a mouse click on the button) into the execution of the logic that modifies the state (addition of one to the value). The final result of this refactoring will be a Traditional MVC design[^1].

In Traditional MVC, the Document is called Model, and its role and structure is unchanged: it stores state and delivers change notifications. The View part is divided into two classes, the Controller and the View. Once instantiated and connected, Model, View, and Controller form a so-called MVC triad.

FIXME Put a more appropriate image, expressing the strong and weak association between entities.

The Controller's role is to transform primary events delivered by the View into operations on the Model. Depending on the specifics of the application, a Controller may or may not need a reference to the View, but it certainly needs the Model to apply changes on

class Controller(object):
   def __init__(self, model, view):
       self._model = model
       self._view = view

The method addOne performs the specific task of transforming a primary event into a Model operation, adding one to the current value. Obviously, the Controller does so through the Model interface. This operation will trigger a Model notification to its listeners

class Controller(object):
    # ...
    def addOne(self):
        self._model.setValue(self._model.value()+1)

At initialization, the View instantiates its associated Controller, passing itself and the Model as parameters. As before, the View registers itself on the Model via the register method

class View(QtGui.QPushButton):
    def __init__(self, model):
        super(View, self).__init__()
        self._model = model
        self._controller = Controller(self._model, self)
        self._model.register(self)

The View now depends on the Controller to modify the Model: only strictly GUI-related handling is done by the View. Conversion from GUI events to application business logic is delegated to the Controller in mouseReleaseEvent

class View(QtGui.QPushButton):
    # ...
    def mouseReleaseEvent(self, event):
        super(View, self).mouseReleaseEvent(event)  
        self._controller.addOne()  

    def notify(self):
        self.setText(unicode(self._model.value()))   

Clicking on the View button will result in a call to Controller.addOne, in turn triggering a call to notify that updates the text label. The activity diagram shows the dance of calls presented above. Note how the Model-View synchronization does not involve the Controller

To initialize the MVC triad, the client code needs to create the Model and View, and let them be aware of each other by passing the Model to the View.

app = QtGui.QApplication(sys.argv)

model = Model()
view = View(model)
view.show()

app.exec_()

The activity diagram shows the setup code given above

This schema assumes that the controller is initialized by the View. This is generally desirable, given that View and Controller are so dependent and tailored to each other that passing the Controller from outside is not profitable.

FIXME The direct connection between View and Controller is needed for:

  1. the View initializes the controller with an instance of itself at creation
  2. the currently active controller can be found by traversing the view hierarchy

FIXME combining two or more roles on the same class can be an acceptable compromise, whose cost is a reduction in flexibility and clarity, and whose advantage is a more streamlined approach for simple cases. Note that mixing the roles does not imply that the code responsible for each of these roles should mix as well. it is in fact good practice to keep the code performing each role in separate routines. This simplifies both understanding and future refactoring, if the needs emerges.

[^1] The more knowledgeable reader may recognize that this MVC model is not the original MVC as intended in the 70s. We will go into detail of the differences in later chapters. What is presented here is the modern reinterpretation of the original MVC, and the one most likely to be intended when talking about "MVC". To clarify the overloaded nomenclature, I chose to refer to the original '70s design as "Reenskaug MVC", and its modern reinterpretation here presented as "Traditional MVC".