PDA

Volledige versie bekijken : [MVC-pattern] initialisation


barn
%Europe/Berlin %561 %2008, 13:28
Hoi,

Ik ben me aan het verdiepen in het MVC-pattern en stuit even op een onduidelijkheid. Het gaat er om wie-wie initialiseert, en wie-van-wie-weet, en wie Sprite extend en wie EventDispatcher extend.

Ik zal mijn situatie schetsen:
Main class
Model class
View class
Controller class

In de Main creeer ik de Controller:

this._c = new Controller('data.xml');

In de constructor van de Controller:

this._m = new Model();
this._v = new View(this._m, this);

this._m.loadData('data.xml');

In de constructor van de View:

this._m = model;
this._c = controller;

_m.addEventListener(Event.INIT, init); // to listen when model is finished initialising, so the view can initialise


Nu mijn vragen...
- is dit de/een goede manier van opbouw, want ik las hier (http://www.dossier-andreas.net/software_architecture/mvc.html) dat eerst een view aangemaakt wordt met een reference naar het model.
- hoe zorg ik bijvoorbeeld dat de controller weet dat de view geinitialiseerd is? Ook via een Event? Maar de view extends al Sprite, en kan dus niet meer EventDispatcher extenden?

Dus ik snap het principe van het MVC model, alleen ik kom een beetje in de knoei met het opzetten/initialiseren van de verschillende delen, en het goed te laten luisteren en versturen van events.

Alvast bedankt voor het zetje in de rug.

barn
%Europe/Berlin %696 %2008, 16:42
Ok, mijn bovenstaande bericht was misschien niet heel duidelijk. Ik zal het nu wat duidelijker proberen neer te zetten:

Ik heb de initialisatie van het MVC model nu gedaan volgens wat hier (http://www.dossier-andreas.net/software_architecture/mvc.html) stond.

Hier de code:

package {
import flash.display.Sprite;

public class Main extends Sprite {

public function Main() {
init();
}

private function init():void {
var model = new Model();
var view = new View( model );

addChild(view);

model.loadData('data.xml');
}
}

}
package {

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.URLLoader;
import flash.net.URLRequest;

public class Model extends EventDispatcher
{

private var _xml:XML;

public function Model()
{
init();
}
private function init():void
{

}

public function loadData(XML_URL:String):void
{
var myXMLURL:URLRequest = new URLRequest(XML_URL);
var myLoader:URLLoader = new URLLoader(myXMLURL);
myLoader.addEventListener(Event.COMPLETE, processXml);
}

private function processXml(e:Event):void
{
this._xml = XML(e.target.data);

// Dispatch Event for VIEW to draw itself!
dispatchEvent(new Event(Event.INIT));
}

}
}
package {
import flash.display.Sprite;
import flash.events.Event;

public class View extends Sprite {

private var _m:Model;
private var _c:Controller;

public function View( model:Model )
{
this._m = model;

_m.addEventListener(Event.INIT, initView);
_m.addEventListener(Event.CHANGE, changeView);

this._c = new videoPlayerController(this._m, this);
}
private function initView(e:Event):void
{
trace('INIT VIEW');
}
private function changeView(e:Event):void
{
trace('CHANGE VIEW');
}
}
}
package {

import flash.events.Event;

public class Controller {

private var _m:Model;
private var _v:View;

public function Controller(model:Model, view:View) {
this._m = model;
this._v = view;

this.init();
}
private function init():void {
trace('INIT CONTROLLER');
}
}

}


Het enige wat me nog niet helemaal duidelijk is hoe ik de communicatie tussen de View en de Controller ga doen. De View kan geen events via dispatchEvent uitzenden. Moet ik dan gewoon functies bijvoorbeeld van een button in de View koppelen aan de API van de Controller? Of moet de Controller toch op de een of andere manier naar Events luisteren van de View.

Ben ik op de goede weg?

matzo
%Europe/Berlin %712 %2008, 17:05
Heb je al eens geprobeerd events te sturen vanuit de view?

View extend namelijk de sprite, en kan EventDispatcher dus niet meer extenden. Maar dat is geen probleem, want EventDispatcher zit al in de hierarchie van de View! Sprite extend namelijk ook gewoon EventDispatcher, en kan dus ook gewoon via DispatchEvent(); een event broadcasten.

Als ik dus nu in de View DispatchEvent(); gebruik, gaat de compiler eerst kijken of DispatchEvent wordt gedefinieerd in View, vervolgens in Sprite, en vervolgens ook in de superclass van Sprite. Zo verder Sprite -> DisplayObjectContainer -> InteractiveObject -> DisplayObject -> EventDispatcher, en bij deze laatste vind hij dan de invuling van de DispatchEvent() functie.

theFlashWizard
%Europe/Berlin %074 %2008, 01:46
barn,
Ik persoonlijk zou vanaf de view methods aanroepen in zijn controller. Dit is volgens mij vooral makkelijker omdat er vaak niet veel verandert is en je info makkelijker via function parameters kan meegeven. Anders zou je heel veel custom events moeten schrijven.
Een ander voordeel is dat je (volgens mij) de controller meer loskoppeld van de view, hij hoeft namelijk niet te weten wat voor events de view dispatcht. Hij heeft gewoon een aantal public methods. Het voordeel daarvan is dat je bijv. makkelijker een algemene controller kan gebruiken voor meerdere views. Als je dan meer nodig hebt kun je altijd nog een extra controller schrijven.

Jij geeft nu ook de view mee naar de controller. Als je niet via events werkt is dat ook niet nodig.

Veel mensen gebruiken een singleton (max 1) model, omdat die makkelijker vanaf verschillende plekken aan te roepen. Het nadeel is dan alleen dat je maar 1 zo'n model in je project kan gebruiken.

In jou geval maak je 1 view, je bent je er van bewust dat men vaak meerdere views heeft (voor overzicht)? Dus vaak voegt men meerdere subclasses van een View class aan een project toe.

Wat Sprite en andere classes nou precies extenden kun je heel makkelijk in flash help/livedocs terug vinden:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/Sprite.html
Deze posters zijn ook erg handig voor overzicht:
Actionscript Tutorials -> posters (http://www.flashfocus.nl/forum/showthread.php?t=6338#posters)

De Kale
%Europe/Berlin %390 %2008, 09:22
zolang als je je model en je ui maar apart houdt, heb je al een ongelofelijke verbetering in je code gemaakt (layering). De controller brengt vaak alleen maar complexitiet mee om deze te gebruiken in flash en kan meestal achterwege gelaten worden.

De view(s) moeten sowieso op muisinteractie reageren, dus een controller zou je (bij gebrek aan andere input manieren bij flash) alleen hoeven te gebruiken voor eventuele keyboard input. Mede hierom is een controller voor flash meestal overkill.

Je kan direct via de view het model benaderen via zijn publieke api en de meest gebruikelijke manier is idd om het model als referentie mee te geven aan de view.

@flashwizard: Overigens denk ik dat je beter een facade kunt schrijven als je meerdere modellen hebt, zodat je nog steeds vanaf de buitenkant 1 model benadert (de facade). dat maakt het een stuk eenvoudiger om je datamodel en je view clean te houden.

theFlashWizard
%Europe/Berlin %425 %2008, 10:12
Hey De Kale,
Ik bedoelde niet met meerdere moddels zoiets als Proxy's in PureMVC. Ik bedoelde meer in de gevallen dat een complex menu of iets dergelijk zijn eigen mvc krijgt. Zijn Main (initializer) communiceerd dan als view met de main mvc.

TheDutch
%Europe/Berlin %367 %2008, 08:48
Ik bedoelde met meerdere moddels zoiets als Proxy's in PureMVC.
Wel de goede benamingen gebruiken hoor ;).

De Proxy binnen PureMVC is zo'n beetje gelijk aan het bekende DAO (Data Access Object) pattern of CRUD (Create Read Update Delete). Het is bedoeld als een soort van kleine facade voor een DTO (Data Transfer Object) of Value Object :).


Veel mensen gebruiken een singleton (max 1) model, omdat die makkelijker vanaf verschillende plekken aan te roepen. Het nadeel is dan alleen dat je maar 1 zo'n model in je project kan gebruiken.
Je bent bekend met het Multiton pattern (http://en.wikipedia.org/wiki/Multiton_pattern)? Erg handig! Zo hebben wij een ContentHolder class die op meerdere plekken in de applicatie afzonderlijk (andere instanties) opereert maar wel aangeroepen kan worden vanaf elke willekeurige plek aan de hand van een ID.


Dus vaak voegt men meerdere subclasses van een View class aan een project toe.

Bedoel je niet een abstract View class of een View interface?

theFlashWizard
%Europe/Berlin %539 %2008, 12:57
Excuses ik mis een "niet" in die zin P)
Het moest zijn:
"Ik bedoelde niet met meerdere moddels zoiets als Proxy's in PureMVC"

Multiton pattern, interessant. Toevallig had ik dat bijna letterlijk bedacht voor BulkLoader, maar dat vonden hun onduidelijk.
Leuk om te zien dat het ook echt een pattern is.
Men zegt alleen ook weer dat het gevaarlijk is omdat men zo vaak op meerdere plekken die class hard aanmaakt. Daarvoor had men een (singleton) Toolbox class bedacht die referenties opsloeg. Dan kun je de classes op 1 plek maken en overal aanroepen. Zo is het niet meer van belang of het een gewone class / Multiton / Singleton is.
http://www.ibm.com/developerworks/webservices/library/co-single.html

De Proxy binnen PureMVC is zo'n beetje gelijk aan het bekende DAO (Data Access Object) pattern of CRUD (Create Read Update Delete). Het is bedoeld als een soort van kleine facade voor een DTO (Data Transfer Object) of Value Object .
Betekent dit dat een VO/DTO alleen maar public vars enz heeft en dat een Proxy/DAO methods heeft als:
public function get numItems():int;
public function has(i:int):Boolean;
public function get(i:int):*;
public function add(value:*):void;
Hoe denk jij er dan over om met een proxy

ErwinL
%Europe/Berlin %554 %2008, 13:19
Ik ben momenteel ook bezig met een website voorzien van een MVC. Met een beetje zoeken stuitte ik op deze site (http://www.adobe.com/devnet/actionscript/articles/ora_as3_design_patterns.html) .
Op deze site staan links naar twee pdf's, waaronder één die geheel gewijd is aan MVC. Dit document heeft mij een heel eind op weg geholpen. (Let wel op dat de code voorbeelden in dit documenten zo hier en daar wat weggevallen is!)

Ik hoop dat je er wat aan hebt.

TheDutch
%Europe/Berlin %770 %2008, 18:29
http://www.ibm.com/developerworks/webservices/library/co-single.html

Interessant artikel! :)


Betekent dit dat een VO/DTO alleen maar public vars enz heeft en dat een Proxy/DAO methods heeft als:
public function get numItems():int;
public function has(i:int):Boolean;
public function get(i:int):*;
public function add(value:*):void;
Hoe denk jij er dan over om met een proxy
Dat is inderdaad wat het betekent. Alleen ik snap je vraag niet echt: "Hoe denk jij er dan over om met een proxy?"

theFlashWizard
%Europe/Berlin %027 %2008, 00:39
Vond ik ook :)

Nouja in 1 project had ik xml als data invoer. Deze zette ik om naar vo's. Om dit proces makkelijk te maken, had ik deze vo's methods als add gegeven.
Nu ik hier opnieuw over na denk was het netter geweest als de Proxy's, de vo's die ze beheren, vullen aan de hand van xml.
Dat werd iets helderder na je verhaal over DTO's en DAO's.

Hoop het snel een keer via amf te proberen, dan zou je, als ik dat goed begreep binnenkomende data gewoon kunnen casten naar een vo class en klaar ben je.

TheDutch
%Europe/Berlin %237 %2008, 05:42
Fijn dat het je opnieuw aan het denken heeft gezet, dat is altijd goed. Het klopt inderdaad wat je zegt; Je kan, wanneer je aan de backend en frontend precies dezelfde DTO (VO class) hebt, ze heen en weer gooien zonder conversie. Je vult dan je DTO's aan de backend en geeft ze als zodanig door naar de frontend (of andersom natuurlijk bij versturen van data) en kunt ze direct gebruiken :).