JavaScript |角度|中介模式:在AngularJS中消除循环依赖的策略

时间:2016-06-17 20:01:37

标签: javascript angularjs design-patterns mediator event-driven

在AngularJS中实现依赖倒置原则的方法

案例研究:中介模式

通常情况下,实施Mediator / Director需要 Director 同事互相引用。 当Director负责模块 - 生命周期管理(MLM) 时,并不困难:

导演在施工期间自我创建时创建同事:

var Director = function Director($$) {
    ...

    function init(...) {
        _moduleA = new ModuleA(this);
        _moduleB = new ModuleX(this);
        _moduleX = new ModuleX(this);
    }

    function moduleChanged(ref) {
        if (ref === _moduleXYZ) _moduleC.run(ref.datum);
    }

    return this;
};

棘手的部分:角度

AngularJS自动承担了MLM 的负担,因此很难使用上述方法。我们可以稍微修改我们的Director.init方法:

_moduleX = $dependency;
...
_moduleX.init(this);

但[我的]同事需要在施工时提及导演

问题和解释

虽然我的导演 实施为EDM(事件驱动的调解)以避免需要DIP,但我现在需要同事来引用导演:

var Colleague = function Colleague(director) {
    var thus = this;
    ...

    director.publish(director.CHANNELS.SOME_CHANNEL_NAME, data);

    ...
    return this;
};

这是因为Director 必须现在提供模块授权(MA):

var Director = function Director($$) {
    ...

    function subscribe(channel, handler) {
        var args = Array.prototype.slice.call(arguments, 0);
        $rootScope.$on.apply($rootScope, args);
        return this;
    }

    function publish(channel) {
        var args = Array.prototype.slice.call(arguments, 0);
        if (channel in this.CHANNELS) $rootScope.$broadcast.apply($rootScope, args);
        return this;
    }

    return this;
};

那就是说,就DIP / DI而言,实际上没有差异 - 这种方法与更多 Classical 之间的对象参考驱动方法首先提到

所以我的问题是,有什么不同的方式可以优雅地在Angular中强加DIP和MLM而不会遇到框架问题?

关注&潜在的解决方法

  • _colleague.init(this);:BAD
  • _colleague = Colleague.call($dependency, this):健康的单身人士???
  • 拆分州驱动的中介并将Director Interface应用于每个同事
  • Mediator Abstract Class [见下文]

将Director Interface应用于每个同事

Mediator 类导入(DI)到每个同事:

var Mediator = function Mediator($rootScope) {
    ...

    function subscribe(channel, handler) {
        var args = Array.prototype.slice.call(arguments, 0);
        $rootScope.$on.apply($rootScope, args);
        return this;
    }

    function publish(channel) {
        var args = Array.prototype.slice.call(arguments, 0);
        if (channel in this.CHANNELS.SOME_CHANNEL_NAME) $rootScope.$broadcast.apply($rootScope, args);
        return this;
    }

    return this;
};
angular.factory('Mediator', () => Mediator);


var Colleague = function Colleague(Mediator) {
    var thus = this;
    ...

    this.publish(this.CHANNELS.SOME_CHANNEL_NAME, data);

    // export precepts
    Mediator.apply(this);
    this.init = init;
    ...

    return this;
};

但是这个可以剥夺导演根据高级应用程序状态进行调解的机会,因为它不会成为Singleton。 E.G:

if (this.state.patientInfoStepComplete) _module.run(ref.datum);

抽象调解员类

与GoF一样,参与者包括 Mediator ConcreteMediator

  • 中保

    • 定义用于与同事对象进行通信的界面
  • ConcreteMediator

    • 通过协调同事对象实现合作行为
    • 了解并维护其同事

为了更接近DIP,我们可以采取" this.CHANNELS"并将其封装在 Mediator 中,但 ConcreteMediator 仍然需要对它的引用,而且同事需要引用任何提供两者 {{1 }和.CHANNELS

你可能想知道为什么我需要一个"混凝土调解员"当我已经实现了一些"抽象调解员"通过使用.publish(...)无论如何都可以提供请求路由,因为同事使用它来提取频道名称值。原因是,虽然.CHANNELS 可以将一个请求路由到另一个请求,但它只能这样做 - 一个请求 - 而.CHANNELS可以提供一对多处理 AND 以其他方式作为中间件(例如:MA)。

.publish(...)

您使用过或想过的任何想法或模式?

在Angular中注册/访问依赖项的任何很酷的非标准技巧?

在Angular中以任何方式配置在运行时注入到Services的另一个依赖项吗?

在Director内部的运行时调用var _actions = { 'SOME_CHANNEL_NAME': (e, a, b, c) => { $rootScope.emit('a', a); $rootScope.emit('b', b); $rootScope.emitemit('c', c); }, }; function publish() { ... if (channel in this.CHANNELS) _actions[channel].apply(_actions, args); ... }

提供商 - 构建流程的中间件?

angular.constant('contreteMediator', this);

0 个答案:

没有答案