What is the right way to wire together 2 javascript objects?

前端 未结 6 1877
梦如初夏
梦如初夏 2020-12-28 19:34

I\'m currently facing a conundrum: What is the right way to wire together 2 javascript objects?

Imagine an application like a text editor with several different fi

相关标签:
6条回答
  • 2020-12-28 19:39

    I would say, just wire them together:

    function wireTogether() {
      var v = new View();
      var c = new Controller();
      c.setView(v);
    }
    

    But then of course another question raises - how do you test the wireTogether() function?

    Luckily, JavaScript is a really dynamic language, so you can just assign new values to View and Controller:

    var ok = false;
    
    View.prototype.isOurMock = true;
    Controller.prototype.setView = function(v) {
      ok = v.isOurMock;
    }
    
    wireTogether();
    
    alert( ok ? "Test passed" : "Test failed" );
    
    0 讨论(0)
  • 2020-12-28 19:48

    There is also a framework for dependency injection for JavaScript: https://github.com/briancavalier/wire

    0 讨论(0)
  • 2020-12-28 19:52

    I'll try to take a stab at this, but it will be a little difficult without seeing any actual code. Personally, I've never seen anybody do such a specific attempt at (M)VC with JavaScript or IoC for that matter.

    First of all, what are you going to test with? If you haven't already, check out the YUI Test video which has some good info on unit testing with javascript.

    Secondly, when you say "the best way to wire up that aggregation" I would probably just do it as a setter w/the controller

    // 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() );
    

    But this makes some big assumption on how you've designed your controller and view objects already.

    0 讨论(0)
  • 2020-12-28 19:54

    Dependency injection is probably your best bet. Compared to Java, some aspects of this are easier to do in JS code, since you can pass an object full of callbacks into your NotebookController. Other aspects are harder, because you don't have the static code analysis to formalize the interface between them.

    0 讨论(0)
  • 2020-12-28 20:01

    Thanks for the insight. I ended up writing a simple JavaScript dependency injection utility. After debating for a while and your comments, it occured to me that DI was really the right answer because:

    1. It totally separated the concerns of wiring from the business logic while keeping the wiring logic close to the things being wired.
    2. It allowed me to generically provide a "you're all wired up" callback on my objects so that I could do a 3 phase initialization: instantiate everything, wire it all up, call everyone's callbacks and tell them they're wired.
    3. It was easy to check for dependency missing problems.

    So here's the DI utility:

    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();
            }
        }
    
    }
    
    0 讨论(0)
  • 2020-12-28 20:05

    I have a inversion of control library for javascript, I'm pretty happy with it. https://github.com/fschwiet/jsfioc. It also supports events, so if you want to have a startup event thats fine. It could use more documentation...

    http://github.com/fschwiet/jsfioc

    Another (newer?) option, which has better documentation and support, is requireJS (http://requirejs.org/).

    0 讨论(0)
提交回复
热议问题