MVC (Model-View-Controller) introduction simplified

Posted By Thaylin on November 4, 2009

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.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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.

:)


Comments

13 Responses to “MVC (Model-View-Controller) introduction simplified”

  1. [...] MVC (Model-View-Controller) introduction simplified [...]

  2. Ali Tan Ucer says:

    Hi,

    This is a great start for any beginner.
    Quick question. Do you think Model in most cases should be singleton?
    Should you include some info into this about singleton?

    Thanks.
    Ali Tan Ucer

  3. [...] This post was mentioned on Twitter by Lisa Larson-Kelley, Heiko Dreyer. Heiko Dreyer said: MVC for the beginner, in a nutshell: http://tr.im/EmTA (via @lisamarienyc) #flash #mvc [...]

  4. Thaylin says:

    @ Ali Tan Ucer
    To create the model as a singleton would not really be ideal since that would break the loose coupling that comes with the mvc pattern. I’m not saying in some circumstances it can’t be done but ideally the model should be passed via the constructor to keep things easy for unit testing and what not.

    Again though, this really depends on your preference and the scope of the project. A simpler project may not have a need to be so loosely coupled, but it’s always good to look ahead and keep things ready for any possible changes to the project that could happen. It all depends on if you are willing to take the risk and if you understand that you may, in the future, need to decouple those things.

    -Thaylin

  5. SuperDuperNubie says:

    Just wanted to say, GREAT JOB!! Finally a simple walkthough of MVC. I have just started really getting into true OOP and have no prior proframing training of any kind other than being a self tought timeline action scripter. Although i am using the MVC pattern to a certain extent. It tends to get messy and this tutorial has helped clarify things alot.

  6. Barney says:

    Hi.

    Thanks alot for putting this up. I’m new to MVC and was struggling to find a way to get input from textfields (user presses button to validate input) into the controller. I was contemplating putting a reference to the view into the controller somehow, as this seemed the only solution, but no-one else seems to mention that this is ever necessary. Perhaps it’s because it’s often illustrated with things like keyboard events. Anyway, you sound like you know what you’re talking about so I’ve gone with the Thaylin approach!

  7. Thaylin says:

    The Thaylin approach? I love it! :)
    Any other questions feel free to ask.

  8. Cor van Dooren says:

    Thaylin,

    Thanks for the clear explaination!
    I would love to see some more complex MVC structure.

    Regards

  9. byron says:

    According to the figure at the top of the MVC Wiki page, the View is an observer of the Model. Also, according to the figure, the View and the Model have a direct association such that the View can send messages to the Model.

    When I look at your code, I don’t see examples of these associations. In addition, it looks like you have the Controller being an observer of the Model, which is an association which doesn’t appear on the figure at the top of the MVC Wiki page.

    I am misinterpreting the MVC figure and/or your code?

    Thanks.

  10. Thaylin says:

    Good question Byron.
    The View in this example sits around and only contains the graphical elements. We don’t want to couple the View with the Model too tightly which is why it uses the Controller to do all the functionality and changes. The View will just accept input from the user and dispatch an event which is then handled by the Controller to update the Model or View if necessary. The only thing I do here with regards to the Model pairing with the View is passing the Model into it’s constructor so we can let the Controller know that there’s a Model associated with it.
    Sometimes there may be reasons for using an observer to take over certain responsibilities of the Controller but based on my schooling and a lot of research I did to create the most concise and logical tutorial I could, this is what seems to be the best methodology. Though, there is never really a wrong way to do things and certain projects would require certain levels of changes to occur.
    Remember this is a pattern, which is based on many people running across this type of interaction between objects throughout the years. As such, it does not need to be strictly followed but merely understood that this could come up and this is a good way to handle that interaction. But never complicate things too much if you don’t need to. By adding an observer where you may not need it, you’ve just added another class in which you would have to look when errors occur, complicating your project to the nth degree depending on how much of that you do.
    My mantra in programming is “The less typing the better”. :)

  11. The example doesnt work for me :(

  12. Very nice tutorial, thank’s for this!!!

  13. [...] Thaylin shows a good example how to avoid this problem. Thus, instantiate Model class(not Singleton) and pass it to a View instance. Quoted what he saids about implementing Model as Singleton. [...]

Leave a Reply

Please note: Comment moderation is currently enabled so there will be a delay between when you post your comment and when it shows up. Patience is a virtue; there is no need to re-submit your comment.