MVC è stato coperto in così tanti posti, quindi non ci dovrebbe essere molto da ripetere. In sostanza, si desidera che il grafico a oggetti, gli helper e la logica siano contenuti nel livello del modello. Le visualizzazioni saranno le schermate che vengono espulse per riempire la parte dinamica della pagina (e possono contenere una leggera quantità di logica e di helper). E il controller, che è un'implementazione leggera per servire gli schermi in base a ciò che era disponibile dai grafici degli oggetti, dagli helper e dalla logica.
Modello
Questo dovrebbe essere dove si trova la carne dell'applicazione. Può essere suddiviso in livelli di servizio, livello logico e livello entità. Cosa significa questo per il tuo esempio?
Livello di entità
Questo dovrebbe contenere le definizioni dei modelli di gioco e dei comportamenti interni. Ad esempio, se avessi un gioco per dragamine, questo sarebbe dove le definizioni del tabellone e del quadrato erano insieme a come cambiano il loro stato interno.
function Location(x,y){
this.x = x;
this.y = y;
}
function MineTile(x,y){
this.flagged = false;
this.hasMine = false;
this.pristine = true;
this.location = new Location(x,y);
}
MineTile.prototype.expose = function(){
if( this.hasMine ) return false;
this.pristine = false;
return this.location;
};
Quindi il MineTile conoscerà il suo stato interno, ad esempio se sta mostrando o è stato esaminato ( this.pristine
), se era una delle tessere che ha una miniera ( this.hasMine
) ma non determinerà se doveva avere una miniera. Questo dipenderà dal livello logico. (Per andare ancora oltre in OOP, MineTile potrebbe ereditare da una tessera generica).
Livello logico
Ciò dovrebbe contenere i modi complessi in cui l'applicazione interagirà con il cambiamento delle modalità, il mantenimento dello stato, ecc. Quindi questo sarebbe il punto in cui verrebbe implementato un modello di mediatore per mantenere lo stato del gioco attuale. Questo sarebbe dove risiedeva la logica di gioco per determinare cosa succede durante una partita per esempio, o per impostare quali MineTiles avranno una miniera. Effettuerebbe chiamate nel livello Entity per ottenere livelli istanziati in base a parametri determinati logicamente.
var MineSweeperLogic = {
construct: function(x,y,difficulty){
var mineSet = [];
var bombs = 7;
if( difficulty === "expert" ) bombs = 15;
for( var i = 0; i < x; i++ ){
for( var j = 0; i j < y; j++ ){
var mineTile = new MineTile(i,j);
mineTile.hasMine = bombs-- > 0;
mineSet.push(mineTile);
}
}
return mineSet;
},
mineAt: function(x,y,mineSet){
for( var i = 0; i < mineSet.length; i++ )
if( mineSet[i].x === x && mineSet[i].y === y ) return mineSet[i];
}
};
Livello di servizio
Questo è dove il controller ha accesso. Avrà accesso al livello logico per la costruzione dei giochi. È possibile effettuare una chiamata di alto livello nel livello di servizio per recuperare un gioco completamente istanziato o uno stato di gioco modificato.
function MineSweeper(x,y,difficulty){
this.x = x;
thix.y = y;
this.difficulty = difficulty;
this.mineSet = MineSweeperLogic.construct(x,y,difficulty);
}
MineSweeper.prototype.expose = function(x,y){
return MineSweeperLogic.mineAt(x,y,this.mineSet).expose();
}
controllore
I controller dovrebbero essere leggeri, in sostanza questo è ciò che è esposto come client al modello. Ci saranno molti controller, quindi strutturarli diventerà importante. Le chiamate alle funzioni del controller saranno quelle che le chiamate javascript hanno riscontrato in base agli eventi dell'interfaccia utente. Questi dovrebbero esporre i comportamenti disponibili nel livello di servizio e quindi popolare o in questo caso modificare le viste per il client.
function MineSweeperController(ctx){
var this.context = ctx;
}
MineSweeperController.prototype.Start = function(x,y,difficulty){
this.game = new MineSweeper(x,y,difficulty);
this.view = new MineSweeperGameView(this.context,this.game.x,this.game.y,this.game.mineSet);
this.view.Update();
};
MineSweeperController.prototype.Select = function(x,y){
var result = this.game.expose(x,y);
if( result === false ) this.GameOver();
this.view.Select(result);
};
MineSweeperController.prototype.GameOver = function(){
this.view.Summary(this.game.FinalScore());
};
Visualizza
Le viste dovrebbero essere organizzate in relazione ai comportamenti del controller. Probabilmente saranno la parte più intensa della tua applicazione poiché si occupa del canvasing.
function MineSweeperGameView(ctx,x,y,mineSet){
this.x = x;
this.y = y;
this.mineSet = mineSet;
this.context = ctx;
}
MineSweeperGameView.prototype.Update = function(){
//todo: heavy canvas modification
for(var mine in this.mineSet){}
this.context.fill();
}
Quindi ora hai la tua intera configurazione MVC per questo gioco. O almeno, un esempio di ossa nude, scrivere l'intero gioco sarebbe stato eccessivo.
Una volta fatto tutto ciò, ci sarà bisogno di un ambito globale per l'applicazione da qualche parte. Ciò manterrà la durata del controller corrente, che è il gateway per tutto lo stack MVC in questo scenario.
var currentGame;
var context = document.getElementById("masterCanvas").getContext('2d');
startMineSweeper.click = function(){
currentGame = new MineSweeperController(context);
currentGame.Start(25,25,"expert");
};
L'uso dei modelli MVC è molto potente, ma non preoccuparti troppo di aderire ad ogni sfumatura di essi. Alla fine, è l'esperienza di gioco che determinerà se l'applicazione ha successo :)
Per considerazione: non lasciare che gli astronauti dell'architettura ti spaventino di Joel Spolsky