...ndid, the somewhat small but happy love child of Nicolás Delfino. A company specialized in interactive websites and rich media applications, knee deep in actionscript and down with jazz...


Posts Tagged ‘analogy’

AS3 MVC Example and Analogy – revised

Posted on: December 3rd, 2010

These last couple of weeks I´ve been struggling at home trying to learn the mvc design pattern. The problem for me when learning new things, specially code related, is that the logic engine of my brain usually shuts off at the beginning of my journey, blocking the way of all common sence needed to explore unknown territories and instead gets replaced with an unhealthy dose of obsession.

That being said, what happend was that I started reading tons of blog posts and articles about mvc, began staying up all night, downloaded every example I could find and drank to much coffee until I got to a point where I´d managed to write a simple application without having a single clue of How and specially Why it all worked…

So there I was, dressed in a stinky wife-beater t-shirt staring at my monitors when a mail delivery (door mail) made me remember two things I´d totally forgoten; namely, that prior to the awesome week I just talked about I´d ordered a book called Actionscript 3.0 Design Patterns, I had also joined lynda.com as a monthly subscriber (thanks mom).

This was exactly what worked for me, what I needed in order to get back some of that common sence I´d lost.

The lynda.com oop training cource is a great resource for newly wedded as3 developers wanting to learn how to write smarter code, and the first couple of hours are great for cathing up on stuff (though it gets more complex along the way). And though I nowadays feel more at ease writing prettier code, it was hours well spent.

Actionscript 3.0 Design Patterns is my number one go to reference when in doubt, just a great book with a lot of common sence and a huge collection of different design patterns ( yes there´s plenty of them – totally freaked when I first opened it but more on that in another post…)

Long story I know but that certain combination of video and hard copy really helped me understand the mvc pattern for what it really is, wich now leads me to the whole purpose of this blog post.

MVC Analogy

I decided that from now on when I face a problem that keeps me up all night I´m going to try to write an example and post it on my blog, …well not Every single time ( I´d had enough material for a book if I did )

1. The Model aka “Blind Mr Miyagi”:

So the easiest way of understanding mvc (wich btw stands for model, view, controller) is to look at it as if there were three guys sitting in seperate rooms:

The first guy, the model is like an awesome karate master, and blind. Like a very wise and blind Mr Miyagi that speaks (well shouts actually) and acts only when it´s absolutely necessary…

A kind of a know-it-all that holds all the juicy information regarding the state of your application.

Though open minded, when it comes to changes in his department he only listens to one man – Hagrid the Groundskeeper (the controller, more on why later…)

2. The View aka “Perez Hilton”:

The second guy, the view is like an artist with serious needs of attention, particularly from Mr Miyagi. He is social in nature and feeds from everything that happens around him, and though he might sound annoying, he´s good little trooper who loves to work!

Besides giving the ocacional poke to Hagrid (his younger brother whom we still haven´t talked about) he´s also the one in charge of everything visual in your application, constantly listening for gossip from Mr Mijagi (the model) so that he´ll get to do what he does best – update the screen

3. The Controller aka “Hagrid the groundskeeper”:

Last but not least we have the third guy, the controller. A loving character that´s kind of all over the place, interacts with everyone, strong but humble with a huge respect for the chain of command.

In his world Perez Hilton´s word is final (family rules you know), has leverage over Mr Miyagi somehow and gets to tell him what to do

Hagrid´s role as the younger brother means hard work as he is also responsible for instantiating the View (Perez) and initiating the Model (Mr Miyagi), telling the Model that it´s time to wake up!

Basic MVC example

This example is a simple and in some ways useless application that does this:

From a user´s point of view:

  1. It tells you to click somewhere on stage
  2. The square moves to where you last clicked and the trace textfield tells you the exact x and y values

Behind the scenes:

  1. It all starts with Hagrid instantiating Perez and initiating Mr Miyagi.
  2. Miyagi now aware of Perez´s existence gets all his shit together (data) and then shouts “Ok Perez I´m good to go!”
  3. Newly born Perez Hilton, bored out of his mind now starts listening for a mouse click
  4. When the user clicks somewhere on the stage Perez goes nutz and sets the x and y properties of his younger brother Hagrid via a setter method, then he goes for a walk.
  5. Hagrid says “ok fine”, alters his private x and y values and walkes over to Mr Miyagi, to whom he does the same thing that Perez did only now it´s everything but civilized, he punches Miyagi in the face and sets his x and y´s.
  6. Mr Miyagi, in chock from the brutal bashing he just received experiences difficulties with his voice (Hagrid has huge fists and must´ve covered a big part of Miyagis´s throat, perhaps even his entire body). Luckily for us Mr Miyagi comes from the ancient family called Event Dispatchers meaning everyone in his family receives a super cool megaphone capable of dispatching information to whoever that´s listening (when they´re of age of cource).
  7. Miyagi walks over to his update method (like a speaker podium), picks up his megaphone and starts ranting “my x and y´s have been altered! check out my new values!” over and over again…
  8. Perez, coming home from his walk hears Mr Miyagi´s rantings and runs straight over to the little squared sprite wich he magically drew in the beginning of the application when it all started.
  9. He picks up the sprite, walks over to his sprite moving machine (the sprite_moveHandler), checks Miyagi´s values and ever so gently puts it down on its new location.

The main document class (mum):

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import mvc.move.controller.Controller;
	import mvc.move.model.Model;
	import mvc.move.view.TraceView;
	import mvc.move.view.View;

	[SWF(width = "635", height = "300", frameRate = "30", backgroundColor = "#D5EAFF")]
	public class Main extends Sprite
	{
		public function Main():void
		{
			this.addEventListener(Event.ADDED_TO_STAGE, init);
		}

		private function init(e:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);

			var model:Model = new Model();
			var controller:Controller = new Controller(model, stage);
		}
	}
}

The Model (Mr Miyagi):

package mvc.move.model
{
	import flash.events.Event;
	import flash.events.EventDispatcher;

	public class Model extends EventDispatcher
	{
		private var _currentX:Number;
		private var _currentY:Number;

		public static const MODEL_INIT:String = "modelInit";
		public static const SPRITE_MOVE:String = "spriteMove";

		public function Model()
		{
		}

		public function init():void
		{
			// get data here
			dispatchEvent(new Event(MODEL_INIT));
		}

		private function update():void
		{
			dispatchEvent(new Event(SPRITE_MOVE));
		}

		public function get currentX():Number { return _currentX; }

		public function set currentX(value:Number):void
		{
			_currentX = value;

			update();
		}

		public function get currentY():Number { return _currentY; }

		public function set currentY(value:Number):void
		{
			_currentY = value;
			update();
		}
	}
}

The View (Perez Hilton):

package mvc.move.view
{
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import mvc.move.controller.Controller;
	import mvc.move.model.Model;

	public class View extends Sprite implements IView
	{
		private var _model:Model;
		private var _controller:Controller;
		private var _target:Stage;

		private var _sprite:Sprite = new Sprite();

		public function View(model:Model, controller:Controller, target:Stage)
		{
			_model = model;
			_controller = controller;
			_target = target;

			addSprite();

			_model.addEventListener(Model.MODEL_INIT, modelInit);
		}

		public function modelInit(e:Event):void
		{
			_model.addEventListener(Model.SPRITE_MOVE, sprite_moveHandler);
			_target.addEventListener(MouseEvent.CLICK, mouse_clickHandler);
		}

		public function sprite_moveHandler(e:Event):void
		{
			_sprite.x = _model.currentX;
			_sprite.y = _model.currentY;
		}

		private function mouse_clickHandler(e:MouseEvent):void
		{
			trace("x: " + mouseX + " y: " + mouseY);
			_controller.newX = mouseX;
			_controller.newY = mouseY;
		}

		private function addSprite():void
		{
			_sprite.graphics.beginFill(0x95A0B5, 1);
			_sprite.graphics.drawRect(0, 0, 20, 20);
			_sprite.graphics.endFill();
			_sprite.x = _target.stageWidth / 2 + 10;
			_sprite.y = _target.stageHeight / 2 + 10;
			_target.addChild(_sprite);
		}
	}
}

The Controller (Hagrid):

package mvc.move.controller
{
	import flash.display.Stage;
	import flash.events.Event;
	import mvc.move.model.Model;
	import mvc.move.view.IView;
	import mvc.move.view.TraceView;
	import mvc.move.view.View;

	public class Controller
	{
		private var _model:Model;
		private var _newX:Number;
		private var _newY:Number;
		private var _stage:Stage;

		public var view:IView;
		public var traceView:IView;

		public function Controller(model:Model, stage:Stage)
		{
			_model = model;
			_stage = stage;

			view = new View(_model, this, _stage);
			traceView = new TraceView(_model, this, _stage);

			model.init();
		}

		public function set newX(value:Number):void
		{
			_newX = value;
			_model.currentX = _newX;
		}

		public function set newY(value:Number):void
		{
			_newY = value;
			_model.currentY = _newY;
		}
	}
}

The TraceView:

package mvc.move.view
{
	import flash.events.*;
	import flash.display.*;
	import flash.events.Event;
	import flash.text.AntiAliasType;
	import flash.text.GridFitType;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import mvc.move.controller.Controller;
	import mvc.move.model.Model;

	public class TraceView extends Sprite implements IView
	{
		private var _model:Model;
		private var _controller:Controller;

		private var _traceDisplay:TextField = new TextField();
		private var _target:Stage;

		public function TraceView(model:Model, controller:Controller, target:Stage)
		{
			_model = model;
			_controller = controller;
			_target = target;

			_model.addEventListener(Model.MODEL_INIT, modelInit);
			_model.addEventListener(Model.SPRITE_MOVE, sprite_moveHandler);
		}

		public function modelInit(e:Event):void
		{
			addTraceField();
			_model.addEventListener(Model.SPRITE_MOVE, sprite_moveHandler);
		}

		public function sprite_moveHandler(e:Event):void
		{
			_traceDisplay.text = "X: " + _model.currentX + " Y: " + _model.currentY;
		}		

		private function addTraceField():void
		{
			// input and display text:
			var t_textFormat:TextFormat = new TextFormat();
			t_textFormat.align = TextFormatAlign.LEFT;
			t_textFormat.size = 10;
			t_textFormat.bold = true;
			t_textFormat.font = "Arial";
			t_textFormat.leftMargin = 10;

			// text display:
			_traceDisplay = new TextField();
			_traceDisplay.defaultTextFormat = t_textFormat;
			_traceDisplay.width = 200;
			_traceDisplay.height = 16;
			_traceDisplay.selectable = false;
			_traceDisplay.textColor = 0x796753;
			_traceDisplay.type = TextFieldType.DYNAMIC;
			_traceDisplay.x = _target.stageWidth / 2 - _traceDisplay.width / 2;
			_traceDisplay.y = _target.stageHeight / 2 - 30;
			_traceDisplay.border = true;
			_traceDisplay.borderColor = 0xD3C9BE;
			_traceDisplay.text = "CLICK ON STAGE";
			_traceDisplay.multiline = true;
			_traceDisplay.wordWrap = true;
			_traceDisplay.background = true;
			_traceDisplay.backgroundColor = 0xDFD7D0;

			_target.addChild(_traceDisplay);
		}
	}
}

The IView Interface:

package mvc.move.view
{
	import flash.events.Event;

	public interface IView
	{
		function modelInit(e:Event):void

		function sprite_moveHandler(e:Event):void
	}

}