MVC освещался во многих местах, поэтому повторять здесь нечего. По сути, вы хотите, чтобы ваш граф объектов, помощники и логика содержались на уровне модели. Представления будут экранами, которые выталкиваются, чтобы заполнить динамическую часть страницы (и могут содержать небольшое количество логики и помощников). И контроллер, который является легкой реализацией для обслуживания экранов на основе того, что было доступно из графов объектов, помощников и логики.
модель
Это должно быть, где мясо приложения сидит. Он может быть разбит на уровни обслуживания, логического уровня и уровня сущности. Что это значит для вашего примера?
Слой сущности
Это должно содержать определения моделей вашей игры и внутреннего поведения. Например, если у вас была игра для тральщика, именно здесь должны быть определения доски и квадрата, а также то, как они изменяют свое внутреннее состояние.
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;
};
Таким образом, MineTile будет знать свое внутреннее состояние, например, показывает ли он или был проверен ( this.pristine
), если это был один из фрагментов, у которого есть mine ( this.hasMine
), но не будет определять, должен ли он иметь мой. Это будет до уровня логики. (Чтобы пойти еще дальше в ООП, MineTile может наследовать от общего Tile).
Логический слой
Это должно содержать сложные способы взаимодействия приложения с изменением режимов, сохранением состояния и т. Д. Таким образом, именно здесь будет реализован шаблон посредника, чтобы поддерживать состояние текущей игры. Именно в этом и заключается логика игры, например, для определения того, что происходит во время игры, или для настройки шахты MineTiles. Это сделало бы вызовы в слой Entity для получения экземпляров уровней, основанных на логически определенных параметрах.
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];
}
};
Сервисный уровень
Это будет где контроллер имеет доступ к. Он будет иметь доступ к логическому слою для построения игр. Вызов высокого уровня может быть сделан в сервисный уровень для того, чтобы получить полностью конкретную игру или измененное игровое состояние.
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();
}
контроллер
Контроллеры должны быть легковесными, по сути это то, что выставляется как клиент модели. Будет много контроллеров, поэтому структурирование их станет важным. Вызовы функций контроллера будут тем, что вызовет JavaScript, основываясь на событиях пользовательского интерфейса. Они должны раскрывать поведение, доступное на уровне сервиса, а затем заполнять или в этом случае изменять представления для клиента.
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());
};
Посмотреть
Представления должны быть организованы относительно поведения контроллера. Они, вероятно, будут самой интенсивной частью вашего приложения, поскольку оно связано с холстом.
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();
}
Итак, теперь у вас есть все настройки MVC для этой игры. Или, по крайней мере, простой пример, выписывание всей игры было бы чрезмерным.
Как только все это будет сделано, где-то для приложения потребуется глобальная область действия. Это сохранит время жизни вашего текущего контроллера, который является шлюзом для всего стека MVC в этом сценарии.
var currentGame;
var context = document.getElementById("masterCanvas").getContext('2d');
startMineSweeper.click = function(){
currentGame = new MineSweeperController(context);
currentGame.Start(25,25,"expert");
};
Использование шаблонов MVC очень эффективно, но не стоит слишком беспокоиться о соблюдении каждого их нюанса. В конце концов, именно игровой опыт определит успешность приложения :)
Для размышления: не позволяйте астронавтам архитектуры пугать вас, Джоэл Спольски