MVC è stato coperto in così tanti posti quindi non ci dovrebbe essere molto da ripetere qui. In sostanza, si desidera che il grafico degli oggetti, gli helper e la logica siano contenuti nel livello del modello. Le viste saranno le schermate che vengono espulse per riempire la parte dinamica della pagina (e potrebbero contenere una quantità minima di logica e di aiutanti). 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 in un livello di servizio, un livello logico e un livello di entità. Cosa significa questo per il tuo esempio?
Livello entità
Questo dovrebbe contenere le definizioni dei modelli e dei comportamenti interni del tuo gioco. Ad esempio, se avessi un gioco per dragamine, questo sarebbe dove erano le definizioni di tavole e quadrati e 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 visualizzando o è stato esaminato ( this.pristine
), se era una delle tessere che ha una mina ( this.hasMine
) ma non determinerà se si suppone che abbia una miniera. Questo dipenderà dal livello logico. (Per andare ancora oltre in OOP, MineTile potrebbe ereditare da un Tile generico).
Livello logico
Questo dovrebbe ospitare i complessi modi in cui l'applicazione interagirà con il cambiamento delle modalità, il mantenimento dello stato, ecc. Quindi questo sarebbe dove sarebbe stato implementato un modello di mediatore per mantenere lo stato del gioco corrente. Questo sarebbe il luogo in cui la logica del gioco risiedeva per determinare cosa succede durante una partita, per esempio, o per impostare quali MineTiles avranno una mina. Effettua chiamate nel livello Entità 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 sarà dove il controllore ha accesso. Avrà accesso al livello logico per la costruzione dei giochi. Una chiamata di alto livello può essere effettuata 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();
}
Regolatore
I controller dovrebbero essere leggeri, essenzialmente questo è ciò che viene esposto come client al modello. Ci saranno molti controller, quindi strutturarli diventerà importante. Le chiamate alle funzioni del controller saranno ciò che le chiamate javascript colpiscono in base agli eventi dell'interfaccia utente. Questi dovrebbero esporre i comportamenti disponibili nel livello di servizio e quindi compilare o in questo caso modificare le visualizzazioni 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 controllore. Saranno probabilmente la parte più intensiva della tua applicazione dal momento che si occupa di tele.
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 l'intera configurazione MVC per questo gioco. O almeno, un semplice esempio, scrivere l'intero gioco sarebbe stato eccessivo.
Una volta che tutto è stato fatto, 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 di pattern MVC è molto potente, ma non preoccuparti troppo di aderire ad ogni sfumatura. Alla fine, è l'esperienza di gioco che determinerà se l'applicazione è un successo:)
Per considerazione: Non lasciare che gli astronauti dell'architettura ti spaventino di Joel Spolsky