6

All the program does is you click a button and it tells you how many times you clicked the button in a textfield.

Document Class: This is the entry point of the code.

package {
    import flash.display.MovieClip;

    /**
     * MVCTest.as
     * @author rotaercz
     */
    public class MVCTest extends MovieClip {
        private var _model:Model;
        private var _view:View;
        private var _control:Control;

        public function MVCTest() {
            _model = new Model();
            _view = new View(this);
            _control = new Control(_model, _view);
        }
    }
}

Model Class: The basic model code.

package {

    /**
     * Model.as
     * @author rotaercz
     */
    public class Model {
        private var _totalClicks:int;

        public function AddClick():void {
            _totalClicks++;
        }

        public function get Clicks():int {
            return _totalClicks;
        }

        public function Model() {
            _totalClicks = 0;
        }
    }
}

Control Class: controls both the input and updating of the model and view here.

package {
    import flash.events.MouseEvent;

    /**
     * Control.as
     * @author rotaercz
     */
    public class Control {
        private var _model:Model;
        private var _view:View;

        public function Control(model:Model, view:View):void {
            _model = model;
            _view = view;
            _view.addEventListener(MouseEvent.CLICK, OnClick);
        }

        private function OnClick(e:MouseEvent):void {
            _model.AddClick();
            _view.Text = "clicked " + _model.Clicks;
        }
    }
}

View Class: The visual representation of the program.

package {
    import flash.display.MovieClip;
    import flash.events.EventDispatcher;
    import flash.events.MouseEvent;
    import flash.text.TextField;

    /**
     * View.as
     * @author rotaercz
     */
    public class View extends EventDispatcher {
        private var _parent:MovieClip;
        private var _button:MovieClip;

        private var _dt:TextField;

        public function set Text(s:String):void {
            _dt.text = s;
        }

        public function View(parent:MovieClip) {
            _parent = parent;
            _dt = _parent.getChildByName("dt") as TextField;
            _button = _parent.getChildByName("mcButton") as MovieClip;
            _button.addEventListener(MouseEvent.CLICK, OnClick);
        }

        private function OnClick(e:MouseEvent):void {
            dispatchEvent(e);
        }
    }
}
Howard
  • 3,648
  • 13
  • 58
  • 86
  • if you don't plan on using specific methods on MovieClip (IE: `gotoAndPlay()`, etc.), you should use Sprite instead. also, unlike CPP, the convention for naming functions of a class (except for the constructor) begins with lowercase (IE: `myFunction()` instead of `MyFunction()`) – Chunky Chunk Nov 10 '11 at 23:04
  • of course, that's simply a matter of personal style while one could argue that this convention is even more confusing to have only the constructor's name begin with an uppercase letter. – Chunky Chunk Nov 10 '11 at 23:27
  • 2
    Which in fact is less confusing, it IS the constructor and therefore reflects the class name. Having capitalized members is a big no-no IMO, it's really unclear whether you're addressing a member's instance member or a class's static member. – Creynders Nov 11 '11 at 13:56
  • I would say that correct capitalization is not just a matter of personal style. Adhering to coding conventions makes your work easier for others to read and understand. Not that I manage to do so all the time though :) http://opensource.adobe.com/wiki/display/flexsdk/Coding+Conventions – shanethehat Nov 11 '11 at 14:38
  • 1
    I should have put the example up as a C# example. Then no one would be talking about capitalized members because that is the coding convention for C#. ;) – Howard Nov 11 '11 at 15:27

3 Answers3

3

In the traditional MVC pattern the view does have a direct dependency on the model just as www0z0k wrote, but I too think that's not an ideal solution.

They way you have setup your controller it acts as a mediator between the model and view, and that's certainly a very valid solution.

However, if you want a more direct communication from model to view (it will save you some code) you could create a central eventdispatcher, pass it to the models and let them use the central eventdispatcher to dispatch their update events, then also pass the central eventdispatcher to the view and let the view listen to the events dispatched by the models directly. That way the view doesn't have a direct dependency on the models, yet it still can listen to the events they send. In that case the controller will only translate view events to the models.

Diagram: http://bit.ly/sTSDVT

The controller updates the model directly, but it also listens to the central event dispatcher for updates from the model (if necessary) and translates them to the view. It also listens for view events

The model only has a dependency on the event dispatcher and uses it to dispatch update events.

The view only has a dependency on the event dispatcher and listens to update events from the model. It dispatches its own events too. (You could use the central event dispatcher for that, but I'd not recommend it)

Creynders
  • 4,573
  • 20
  • 21
1

I believe my Introduction to Flex Application’s Architecture - Redux is going to be quite of interest to you.

For a more Flashy approach you can check the FLit Framework. The MVCSprite is very similar to your solution.

Playing with so many frameworks through the years, I came to believe that it's not very pragmatic to pursue the 'correct' and 'ideal' implementation. Design patterns aren't formal - these are just ideas that should always be adjusted according to the quality attributes you're trying to achieve. Keep in mind that it would be a very rare occasion to really nail the approach in a single iteration - sometimes it takes many projects to be completed before you spot a better way - to get to a deeper insight.

Vladimir Tsvetkov
  • 2,983
  • 3
  • 26
  • 36
0

controller listens to view and updates model, this part fits my vision of MVC.
but i'd tried to avoid involving controller in binding model to view:

    _model = new Model();
    _view = new View(this, _model);
    _control = new Control(_model, _view);

in model:

public class Model extends EventDispatcher{
    //............
    public function AddClick():void {
        _totalClicks++;
        dispatchEvent(new Event('one more click'));
    }

in view:

    private var _model:Model;
    public function View(parent:MovieClip, model:Model) {
        _parent = parent;
        _model = model;
        _model.addEventListener('one more click', update);
        _dt = _parent.getChildByName("dt") as TextField;
        _button = _parent.getChildByName("mcButton") as MovieClip;
        _button.addEventListener(MouseEvent.CLICK, OnClick);
    }

    private function update(e:Event):void{
        _dt.text = _model.clicks;
    }
www0z0k
  • 4,444
  • 3
  • 27
  • 32
  • I see what you did there. I understand that the Model is now also dispatching events and the View is listening. However you have to pass the _model instance to the View Constructor. The View now requires a _model for it to work. Why is this better? If there are multiple Models using this View, I would have to add event listeners to View for every single one of them. – Howard Nov 11 '11 at 01:53
  • in such cases i usualy use a static dispatcher, so for every ui element i add a listener to it and every model value change causes an event dispatched by it, while i don't need a model reference in my view – www0z0k Nov 11 '11 at 13:05
  • I'd really recommend against using a static dispatcher, because it ties your classes to a specific instance. What if you decide you want two circuits of event dispatchers instead of one? Then you'll be refactoring all your classes. As a matter of fact static properties should always be avoided except in two cases: consts and properties that reflect class state (for instance an instance counter) – Creynders Nov 11 '11 at 13:58
  • here's the implementation i'm talking about http://stackoverflow.com/questions/4040300/as3-flex-4-most-practical-way-to-find-nested-children/4046561#4046561 and it seems flexible enough to me, because all you need to use it is to add just one string. it's also possible to make multiple channels of global event dispatching – www0z0k Nov 11 '11 at 14:46
  • Obviously there's always a solution, the point was to avoid static access of instances. And actually your response is a good example of what I said, if he'd implemented a static EventDispatcher and then would want to swap it for your Radio class he'd be refactoring every single class. – Creynders Nov 13 '11 at 07:48