在MVC中,三種物件如何互動,是設計的關鍵。基本上目前Controler已經確定了,所以還需要決定View與Model的互動方式。
構想
由於Model可能是MVC三者之中最花時間的,比較好的策略是,先由Model準備好資料,當資料準備好,再呼叫View來呈現。
另外,為了簡化設計,盡量要讓Model與View是一對一的關係,所以傳遞的資料必須匹配:
* View要能直接剖析Model傳過來的資料,並且把它render出來(透過template)
* 從另外一方面來說,Model準備丟給View的資料,必須是View可以處理的
在介面上,目前想到的做法是:
* View與Model都做成獨立的module
* 利用Model的constructor傳入對應的View的instance
* 利用View的constructor,把伺服器實際進行render用的callback傳給它
* 呼叫Model的execute方法,Model會進行查詢,並且準備好要傳遞給View的資料物件
* Model的execute方法會呼叫View的render方法,並且把資料物件傳給它產出呈現的結果
概念性實做
models.js的概念性實做:
module.exports = {
hello: function(view) {
var data = {
name: 'fillano'
};
this.execute = function() {
process.nextTick(function() {
view.render(data);
});
}
}
};
裡面只是提供一個簡單的stub資料,然後與view互動。
views.js的概念性實做:
var hello = 'Hello: {%$name%}';
var varParser = function(str, obj) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
var tmp = new RegExp('\\{%[ ]*\\$'+i+'[ ]*%\\}', 'g');
str = str.replace(tmp, obj[i]);
}
}
return str;
}
module.exports = {
hello: function(cb) {
this.render = function(obj) {
cb(false, '/hello_mvc', {type: 'text/html', data: varParser(hello, obj)});
};
}
};
目前還不實際讀取template檔案,而是先用簡單的stub來代替。html模板的內容放在hello變數中,varParser會從傳入的物件中,把對應的資料放入hello變數中的html模板,產出要呈現的資料,然後呼叫伺服器負責render的callback,把頁面輸出。
然後在整合測試中新增一個測試,首先修改setUp,加入一個router:
.get('/hello_mvc', function (request, response, cb) {
var HelloModel = require('../lib-cov/models').hello;
var HelloView = require('../lib-cov/views').hello;
var m = new HelloModel(new HelloView(cb));
m.execute();
});
然後增加一個叫做"test router hello_mvc"的測試:
"test router hello_mvc": function(test) {
test.expect(3);
var req = this.http.request({
"host": "localhost",
"port": 8443,
"path": "/hello_mvc",
"method": "GET"
}, function(response) {
var result = [];
response.on('data', function(data) {
result.push(data);
});
response.on('end', function() {
var total = 0;
var entity = '';
for(var i=0; i<result.length; i++) {
total += result[i].length;
entity += result[i].toString('utf8');
}
test.equal(200, response.statusCode);
test.ok(entity.indexOf('Hello')>-1);
test.ok(entity.indexOf('fillano')>-1);
test.done();
});
});
req.end();
}
跑過整合測試,看起來這樣的設計有達到設計的目標。
今天的範例檔fillano-evolve-v0.0.18-0-g4d4f485.zip,目前版本是v0.0.18。