[英]What is the right way to wire together 2 javascript objects?
我目前面臨一個難題:將兩個javascript對象連接在一起的正確方法是什么?
想象一下像文本編輯器這樣的應用程序,它有幾個不同的文件。 我有一些HTML頁面代表筆記本的視圖。 我有一個文件notebook.js,其中包含NotebookController和Notebook View的類定義。
NotebookControler對象負責在筆記本上執行業務邏輯,如“保存筆記本”,“加載筆記本”,“新筆記本”。 NotebookView負責管理用於演示的HTML。 它做低級別的東西,如“獲取/設置筆記本電腦主體”“獲取/設置筆記本名稱”。 它還偵聽DOM事件(onClick)並觸發業務事件(saveNotebook)。 這是我對被動視圖模式的嘗試。
我希望我的javascript客戶端代碼是面向對象的,分離的關注點和單元可測試的。 我想用模擬NotebookView測試NotebookController,反之亦然。 這意味着我不能只在NotebookController中實例化NotebookView。 我也是
在Java中,選擇是自然的:使用Spring。 但這似乎不是JavaScript-y。 什么是正確的做法?
依賴注入可能是你最好的選擇。 與Java相比,JS代碼中的某些方面更容易實現,因為您可以將一個充滿回調的對象傳遞到NotebookController中。 其他方面更難,因為您沒有靜態代碼分析來形式化它們之間的接口。
感謝您的見解。 我最終編寫了一個簡單的JavaScript依賴注入實用程序。 經過一段時間的辯論和你的評論之后,我發現DI確實是正確答案,因為:
所以這是DI工具:
var Dependency = function(_name, _instance, _dependencyMap) {
this.name = _name;
this.instance = _instance;
this.dependencyMap = _dependencyMap;
}
Dependency.prototype.toString = function() {
return this.name;
}
CONCORD.dependencyinjection = {};
CONCORD.dependencyinjection.Context = function() {
this.registry = {};
}
CONCORD.dependencyinjection.Context.prototype = {
register : function(name, instance, dependencyMap) {
this.registry[name] = new Dependency(name, instance, dependencyMap);
},
get : function(name) {
var dependency = this.registry[name];
return dependency != null ? dependency.instance : null;
},
init : function() {
YAHOO.log("Initializing Dependency Injection","info","CONCORD.dependencyinjection.Context");
var registryKey;
var dependencyKey;
var dependency;
var afterDependenciesSet = [];
for (registryKey in this.registry) {
dependency = this.registry[registryKey];
YAHOO.log("Initializing " + dependency.name,"debug","CONCORD.dependencyinjection.Context");
for(dependencyKey in dependency.dependencyMap) {
var name = dependency.dependencyMap[dependencyKey];
var instance = this.get(name);
if(instance == null) {
throw "Unsatisfied Dependency: "+dependency+"."+dependencyKey+" could not find instance for "+name;
}
dependency.instance[dependencyKey] = instance;
}
if(typeof dependency.instance['afterDependenciesSet'] != 'undefined') {
afterDependenciesSet.push(dependency);
}
}
var i;
for(i = 0; i < afterDependenciesSet.length; i++) {
afterDependenciesSet[i].instance.afterDependenciesSet();
}
}
}
我會說,只需將它們連接在一起:
function wireTogether() {
var v = new View();
var c = new Controller();
c.setView(v);
}
但當然另一個問題提出了 - 你如何測試wireTogether()函數?
幸運的是,JavaScript是一種非常動態的語言,因此您只需為View和Controller分配新值:
var ok = false;
View.prototype.isOurMock = true;
Controller.prototype.setView = function(v) {
ok = v.isOurMock;
}
wireTogether();
alert( ok ? "Test passed" : "Test failed" );
我有一個javascript控件庫的反轉,我很高興。 https://github.com/fschwiet/jsfioc 。 它還支持事件,所以如果你想要一個很好的啟動事件。 它可以使用更多文檔......
http://github.com/fschwiet/jsfioc
另一個(較新的?)選項,具有更好的文檔和支持,是requireJS(http://requirejs.org/)。
還有一個用於JavaScript依賴注入的框架: https : //github.com/briancavalier/wire
我會嘗試對此進行嘗試,但如果沒有看到任何實際代碼,那將會有點困難。 就個人而言,我從未見過有人在(M)VC上使用JavaScript或IoC進行過這樣的特定嘗試。
首先,你要測試什么? 如果您還沒有,請查看YUI測試視頻 ,其中包含有關使用javascript進行單元測試的一些好信息。
其次,當你說“連接聚合的最佳方式”時,我可能會把它當作一個帶控制器的setter
// Production
var cont = new NotebookController();
cont.setView( new NotebookView() );
// Testing the View
var cont = new NotebookController();
cont.setView( new MockNotebookView() );
// Testing the Controller
var cont = new MockNotebookController();
cont.setView( new NotebookView() );
// Testing both
var cont = new MockNotebookController();
cont.setView( new MockNotebookView() );
但是這對你如何設計控制器和查看對象做了一些很大的假設。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.