It recently came to my attention that while working alone I have lost a bit of the ability to explain programming patterns. It’s not that I’ve forgotten about them, as I use variations of them in everyday work, but I’ve just lost touch with the ability to easily explain the workings of them.
So what better way to refresh myself than to publish some tutorials on them!
Looking through the web I’ve noticed there’s not to many just simplified and easy to understand explanations of MVC, how it really works, and why would one even want to use that as opposed to just coding willy nilly.
I’ll spare you the history of MVC and just send you to the wiki page instead to read for yourself if you want : MVC Wiki
Basically it works like this:
Model – Holds the data and business logic. This item in the triage is what is considered “loosely coupled“, meaning that it knows nothing about the controller or the view. It just sits there doing it’s thing and when something is changed it let’s anyone that may be listening know that something has been changed. In actionscript you would extend the EventDispatcher class. This way it has the ability to dispatch events when updated. It would look something like the code below.
package info.thaylin.model
{
import flash.events.Event;
import flash.events.EventDispatcher;
/**
*
* @author Thaylin Burns
* Stores data and when changed, dispatches events
*/
public class Model extends EventDispatcher
{
public static const SOME_DATA_CHANGED:String = 'someDataChanged'
private var _someData:String = '';
public function Model()
{
}
public function set someData(value:String):void
{
_someData = value;
dispatchEvent( new Event( SOME_DATA_CHANGED ) );
}
public function get someData():String
{
return _someData;
}
}
}
The class above is a very simple Model that just stores a variable “_someData” and has a setter to alert anything listening that the data has changed. There may be other things that need to be done in this level like string manipulation or any other business logic that could occur. All of that should be generally stored in this class.
View – The view is just basically that, the visual part of something. The Graphical User Interface by which a user can interact with your application. This could be buttons, textfields, or various other things. It just contains these elements and no real functionality. That is left to the controller which it is “tightly coupled” to. Below is an example of what you may have as a view to maybe interact with our model from above.
package info.thaylin.view
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
import info.thaylin.controller.Controller;
import info.thaylin.model.Model;
/**
*
* @author thaybur
* Contains the visual elements the user interacts with. There generally shouldn't
* be any functionality that resides within this part of our triage.
*
*/
public class View extends Sprite
{
public var nameInput:TextField = new TextField();
public var addressInput:TextField = new TextField();
public var textContainer:TextField = new TextField();
public var submitButton:Sprite = new Sprite();
private var model:Model;
private var controller:Controller;
public function View(model:Model)
{
this.model = model;
controller = new Controller(this, model);
init();
}
private function init():void
{
nameInput.type = TextFieldType.INPUT;
nameInput.background = nameInput.border = true;
nameInput.width = 200;
nameInput.height = 20;
addChild(nameInput)
addressInput.type = TextFieldType.INPUT;
addressInput.background = addressInput.border = true;
addressInput.width = 200;
addressInput.height = 20;
addressInput.y = 30;
addChild(addressInput);
submitButton.graphics.beginFill(0xCCCCCC);
submitButton.graphics.drawRect(0,0,100, 20);
submitButton.graphics.endFill();
submitButton.addEventListener(MouseEvent.CLICK, submitButton_clickHandler);
submitButton.buttonMode = true;
submitButton.y = 60
addChild(submitButton)
textContainer.type = TextFieldType.INPUT;
textContainer.background = true;
textContainer.selectable = false;
textContainer.width = 200;
textContainer.height = 100;
textContainer.y = 90;
addChild(textContainer)
}
private function submitButton_clickHandler(event:MouseEvent):void
{
dispatchEvent(new Event('submitButtonClick'))
}
}
}
You’ll notice here that we’re passing a reference of the model to the constructor of our View class. This is then passed to the controller along with a reference of our view as “this”. So the model is created in our main class along with our view. We then pass the model to the view and if there’s any default values within the model you might set them at this point in your view. But basically, you see, this view contains no functional methods. We do, however, set a callback for a mouse click event on line 51. That tells our view to dispatch an event of “submitButtonClick” which our controller will be listening for.
Controller – The controller contains the methods in which you will change your view or model. It handles any real functionality, as in the mouse click event set in our view. Here is our controller.
package info.thaylin.controller
{
import flash.events.Event;
import flash.events.MouseEvent;
import info.thaylin.model.Model;
import info.thaylin.view.View;
public class Controller
{
private var model:Model;
private var view:View;
public function Controller(view:View, model:Model)
{
this.view = view;
view.addEventListener('submitButtonClick', submitButton_clickHandler)
this.model = model;
this.model.addEventListener(Model.SOME_DATA_CHANGED, model_changeHandler);
}
public function submitButton_clickHandler(event:MouseEvent):void
{
if(view.addressInput.text && view.nameInput.text)
this.model.someData = view.nameInput.text + '\n' + view.addressInput.text
}
private function model_changeHandler(event:Event):void
{
view.nameInput.text = view.addressInput.text = ''
view.textContainer.text = this.model.someData;
}
}
}
So here you can see we’ve got our controller that gets passed the reference to the view that it’s tightly coupled with and the model. We add an event listener to the model to inform us of when any change has happened and we perform our view changes in that method (model_changeHandler). For instance here we first have a handler for the “submitButtonClick” that is dispatched from the view. This checks if our view’s addressInput.text and nameInput.text values contain something. If so, we set our model’s data to the name text and address text on a separate line.
After the change has been made to the model, it then fires off our “SOME_DATA_CHANGED” event which we then handle in the mode_changeHandler method. In this method we reset our input textfields and set the textContainer text to equal the someData variable in the model.
Why?
So why would we go through all of this shenanigans you say? Just to fill a textbox? Well, no. Generally this is to be used for a bit more complex structures. But just to kinda show you how this could be handy once you’ve set all this up. Let’s implement this view in our main class.
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import info.thaylin.model.Model;
import info.thaylin.view.View;
public class main extends Sprite
{
public function main()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
var model:Model = new Model();
var view:View = new View(model);
addChild(view);
var view2:View = new View(model);
view2.x = 300;
addChild(view2)
}
}
}
So here we’ve implement 2 of our views and passed the same model. Run this and you’ll see two terrible looking little components. Enter text into the left side’s textboxes and hit the grey square we’re calling a button. You’ll notice that both instances’ textContainers update with the same data. Entering text in the one on the right does the same thing.
You may be starting to see how this could be beneficial. Maybe we have a slew of items that could all update a single data source. By loosely coupling your items like this it’s made a lot easier. Maybe you have a View with a single textField that displays the data of either of those views we’ve made, or maybe it even adds the text on a new line.
I hope I’ve at least helped someone a little bit in the understanding of the MVC pattern and how it could be beneficial by using it when needed.
I’ll be doing more of these with the various patterns, trying to make them as simplified as possible. If you can think of anything you’d like to see or if there’s anything you just aren’t quite getting send me a comment and I’ll try and accommodate.
🙂
Leave a Reply
You must be logged in to post a comment.