
Truckin' thru MVC
Adding an Interface for the View
Before adding another view, I wanted to add an interface so that I could use the same Model and Controller classes. The changes are minimal in the revised View classes, and I changed the Client so that it could more easily request any view the user would like. Since you have all of the details about how the MVC works in Parts I-III, I’ll get right into the interface.
In looking at the View class in Part III, you can see that the class has only two methods. By putting them into an interface, we can program to the interface instead of the implementation. That means that as long as the same interface is used, you can use the same Model and Controller without any changes at all. As usual, interfaces are fairly short, and this one is no exception.
1 2 3 4 5 6 7 8 9 10 11 | package { import flash.display.Sprite; import flash.events.Event; public interface IView { function createView(vessel:Sprite):Sprite; function update(e:Event):void; } } |
Before continuing, click the Play button to test both compasses that have their roots in that interface. (compi?)
![]()
The Model and Controller classes are identical for both compass examples. Read on to see how easy it is to add views.
Because we now have an interface for the View, we need to update the original View class so that it implements the IView interface. The name of the View classes need to be unique; so the name has been changed from View to ViewAnalog. Likewise, the createAnalog() method has been given the more general name, createView() in line with the more general task of the method.
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 | package { import fl.controls.Slider; import fl.events.SliderEvent; import flash.display.Sprite; import flash.events.Event; public class ViewAnalog implements IView { private var model:Model; private var controller:Controller; private var base:Sprite; private var compassRose:Sprite; private var pointer:Sprite; private var slider:Slider; public function ViewAnalog(model:Model, controller:Controller, vessel:Sprite) { this.model=model; this.controller=controller; base=createView(vessel); } public function createView(vessel:Sprite):Sprite { //add compass rose and needle compassRose=new CompassRose(); compassRose.x=250,compassRose.y=250; vessel.addChild(compassRose); pointer=new Pointer(); pointer.x=0,pointer.y=0; compassRose.addChild(pointer); //**add slider var slideHolder=new Sprite(); vessel.addChild(slideHolder); slider=new Slider(); slider.maximum=360; slider.width=slider.maximum; slideHolder.addChild(slider); slider.x=(250) - (slider.width/2); slider.y=20; slider.addEventListener(SliderEvent.CHANGE, controller.newDirection); return compassRose; } public function update(e:Event):void { pointer.rotation=model.getDir(); } } } |
As you can see, it’s almost identical to the original View class. Now for the payoff of loose coupling. Instead of an analog compass, this next one is a retro-digital compass. With a black background and green text, it looks like the old monitors with black screens and green output. Placed next to the analog compass, you can see the same exact data in a wholly different framework. Figure 1 compares the different views with the same data:

Figure 1: Adding new views is easy with MVC
The following listings shows the changes that were made. Note that instead of using MovieClip objects for display, this next view uses a Shape for the background and a TextField and TextFormat for the value state in the Model. However, both are placed in the vessel Sprite and work just fine. The same Slider with the same code is reused except instead of changing the rotation, the value is placed in a TextField object.
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 { import fl.controls.Slider; import fl.events.SliderEvent; import flash.display.Sprite; import flash.events.Event; import flash.text.TextField; import flash.text.TextFormat; import flash.display.Shape; public class ViewRetro implements IView { private var model:Model; private var controller:Controller; private var base:Sprite; private var slider:Slider; //Instantiate text field and format private var txtFld:TextField=new TextField(); private var format:TextFormat=new TextFormat(); public function ViewRetro(model:Model, controller:Controller, vessel:Sprite) { this.model=model; this.controller=controller; base=createView(vessel); } public function createView(vessel:Sprite):Sprite { //Create backdrop using a Shape var crt:Shape=new Shape ; crt.graphics.beginFill(0x000000); crt.graphics.lineStyle(0,0x000000); crt.graphics.drawRoundRect(100,60,300,50,6); crt.graphics.endFill(); vessel.addChildAt(crt,0); format.color=0x00ff00; format.font="OCR A Std"; format.size=32; txtFld.defaultTextFormat=format; txtFld.x=220; txtFld.y=70; //Set default value to 0 so that //it does not display null--NaN txtFld.text=0; vessel.addChildAt(txtFld,1); //add slider var slideHolder=new Sprite(); vessel.addChild(slideHolder); slider=new Slider(); slider.maximum=360; slider.width=slider.maximum; slideHolder.addChild(slider); slider.x=(250) - (slider.width/2); slider.y=20; slider.addEventListener(SliderEvent.CHANGE, controller.newDirection); return vessel; } public function update(e:Event):void { txtFld.text=model.getDir(); } } } |
Finally, the Client has to be changed a bit so that selecting one view or another is simple to do. (You can get fancier if you like and set up a UI selection.) The following listing shows the Client.
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 | package { import flash.display.Sprite; public class Client extends Sprite { private var model:Model; private var view:IView; private var controller:Controller; public function Client() { setMVC("r"); } private function setMVC(viewType:String):void { model = new Model(); controller=new Controller(model); switch (viewType) { case "a" : view=new ViewAnalog(model,controller,root); break; case "r" : view=new ViewRetro(model,controller,root); } model.addEventListener(Model.UPDATE, view.update); } } } |
As far as I can see, the MVC fulfills exactly what GoF had intended for it to do—illustrate how by loosening up classes, updating and adding new elements is easy. While I’ve been busy with OOPSLA and work, it took me a good deal of time to develop the original MVC. However, when it came to updating the program, I was able to do it quite quickly. If you’d like to download the entire set of files, click the download button that Barbara Parkman send us.

Make Your Own View
To really understand how the MVC works, you will find it helpful to create your own View for this program. Just add any kind of view you want, from simple to elaborate, and have it display data from the Model. There’s nothing you can break, and it will demonstrate how useful Design Patterns are when adding new elements to a program. In fact, we can make it into a Golden Lunch Bucket Contest if enough of you are interested. Enjoy!

The Truckin’ Through ActionScript 3.0 MVC: Part IV—Making Changes by William B. Sanders, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
Related posts:

Bill Sanders
Why are you registering View with the Model in Client class?
Why doesn’t the View registers itself with the Model , upon initialization (inside the View class)?
So your Client class would only need to create the appropriate instances of MVC and that’s it.
On a side note , Controller doesn’t have a reference to the View, this is not essential but it could be an added functionality, because sometimes Controller needs to speak to View without including Model in to conversation.
Hi Ivan,
The point of this particular post is code re-use and the simple (and trivial) example is to show how easy it is to use the bulk of the code with a different view. So, it’s really about re-use, and I was hoping the comments might reflect that.
The MVC is a fairly flexible framework, and I’d really like to see you take my example and fix it up with your registration process with a different view. Let’s see what you got.
Kindest regards,
Bill
Bill!
Wow! I’m so glad I came across this huge article! I have looked at the surface of MVC for a while now without truly understanding the flow of communication between the segments of code (Model, View and Controller). I now feel enlightened and can’t wait to begin tackling my new applications with this design pattern.
I didn’t quite get the bridge bit about the bridge not being able to stand up with square supports and why it would fall sideways. However I did understand what you meant about solid non-substandard structure code-wise.
Now I do have one particular question. I am working on a Drupal Flash website and I have pretty much written the code for it to work. However, I have all written it in a class called “Interface.as”, i.e. non-MVC. In your example you seperated some pretty simple code into M, V and C with a client to instantiate, but in my application/website as3 code there are various “modules” (if I can call them that) due to the fact that a website doesn’t contain only a compass needle and a slider. It contains more things such as “language selection”, “web pages”, “product photo gallery”, “news”, “menu” etc. Also it contains main site information that remains pretty much constant throughout the site like a variable such as “_siteDomain”. What I can’t seem to get my head around is:
Where do I start?
How do I separate the “modules” and how do they communicate with each other?
How would I go about planning the MVC?
What kind of tools are there to conceptualize an application specific to as3?
Thank you very much for having taken the time to write such an in depth and enlightening article and if you do find the time to answer my questions I would like to thank you in advance.
Best Regards,
Alexandre
Hi Alex,
First of all, Chandima is the real MVC expert here—both MVC and PureMVC. Your questions are all handled better in Chapter 12 than I could in a short note to you. (Also, Chandima could do it better.)
Second, I’m not that enthusiastic about the MVC. GoF make reference to it almost in passing in Chapter 1 of their book, and it is not actually a design pattern so much as it is a heuristic device for helping to understand design patterns. Somehow, it has become the favorite framework for many developers, and so I thought it wouldn’t hurt to look at it and use it as an example of structure. That was what the bridge was for—illustrating different structures.
The best place to start with the MVC or any other design pattern is to ask:
Once that question is addressed, you can then select the design pattern that handles variation. So instead of beginning by asking How do I handle this problem? you need to back away and look at the principles on which design patterns are based.
All of the tools you need for this are pulled together in a Starter Kit on this blog. That will put you on the right path.
Kindest regards,
Bill
Hi Bill,
Great article! Your writing is clear and makes it easy to understand.
If you had to redo the compass example in a way you prefer what would that be? Hopefully you can do your next blog on that.
Thank you,
~mark
Hi Mark,
Good question. I’d have to begin with the main query, “What varies?”. I believe that the Observer pattern would be most useful because different objects (analog and digital compass displays) depend on the information from the object that generates the information.
What do you think?
Kindest regards,
Bill
this is exactly the way i see the mvc.
It looks like not everybody has the same vision of the MVC.
Just check the way cocoa implemented it
http://bark.metacasa.net/2006/07/01/cocoa-mvc/
it looks like the controller has many responsabilities and the model does not notify anything to the view
Hi Gropapa,
Thanks for that link! I didn’t realize Cocoa was designed around the MVC.
Kindest regards,
Bill