62

AngularJS + OOP 使用起来有点性感

嗨,我已经成功地将 OOP 与 AngularJs 一起使用了一段时间(首先从 angularjs 开始,并在操作中使用 oop 继承),所提供的方法允许您将类定义为角度服务,您以后可以像这样扩展或继承它:

Application.factory('AbstractObject', [function () {
    var AbstractObject = Class.extend({
        virtualMethod: function() {
           alert("Hello world");
        },
        abstractMethod: function() { // You may omit abstract definitions, but they make your interface more readable
           throw new Error("Pure abstract call");
        }
    });

    return AbstractObject; // You return class definition instead of it's instance
}]);

Application.factory('DerivedObject', ['AbstractObject', function (AbstractObject) {
    var DerivedObject = AbstractObject.extend({
        virtualMethod: function() { // Shows two alerts: `Hey!` and `Hello world`
            alert("Hey!");

            this._super();
        },
        abstractMethod: function() {
            alert("Now I'm not abstract");
        }
    });

    return DerivedObject;
}]);

Plunker:http ://plnkr.co/edit/rAtVGAsNYggBhNADMeoT

使用所描述的方法使您能够定义完美地集成到 Angular 基础架构中的类。你可以从两个世界——OOP 和 AngularJs 中获得各种漂亮的特性。依赖注入对您的类是免费的,它使您的类变得简单,允许将大量样板控制器代码放入一些以后可以重用的基类中。

然而

AngularJs 基础设施阻止了先前描述的方法,使其无法 100% 地展开它的翅膀。当您尝试定义递归类定义(即递归聚合)时会出现问题,假设您有两个类定义,例如BlogTag

Application.factory('Blog', ['Tag', function (Tag) {
    var Blog = Class.extend({
        tags: function() {
            return this.tags;
        }
    });

    return Blog;
}]);

Application.factory('Tag', ['Blog', function (Blog) {
    var Tag = Class.extend({
        Blogs: function() {
           return this.blogs;
        }
    });

    return Tag;
}]);

它不起作用,因为两者BlogTag自我引用自己导致循环依赖。

附言

最后一件事,我找到了一种丑陋的解决方案,可以在我的特定情况下解决我的问题,但通常不起作用,正如我所说,它并不漂亮:

Application.factory('BlogNamespace', [function () {
    var Blog = Class.extend({
        tags: function() {
            return this.tags;
        }
    });

    var Tag = Class.extend({
        Blogs: function() {
           return this.blogs;
        }
    });

    return {
        Tag: Tag,
        Blog: Blog
    };
}]);

问题

上述修复不起作用,因为命名空间也可能是循环依赖的主题。这意味着它不是描述问题的解决方案,而是现在更深层次的问题。

在一般情况下如何解决所描述的问题有什么建议吗?

4

3 回答 3

70

循环依赖始终是关注点混合的标志,这是一件非常糟糕的事情。AngularJS 的作者之一 Miško Hevery在他很棒的博客上解释了一个很好的解决方案。简而言之,您可能在某处隐藏了第三个服务,这是其他两个真正需要的代码的唯一部分。

于 2013-10-13T12:42:42.000 回答
58

我正在回答我自己的问题,只是因为我找到了一种解决我最初发布的问题的技术方法。但在此之前,我强烈建议您使用 Blackhole 的建议,因为它可以解决通常由不良架构引起的更广泛的问题。请先使用他的方法,如果您知道自己在做什么,请返回当前的方法。

所以这里是:

您可以$injector在运行时使用服务并注入所需的定义,这从技术角度来看是合法的,但再次根据这篇文章(很难想象它是在 2008 年编写的),这就像一个黑魔法,这样做并且它会反击你:

Application.factory('Blog', ['$injector', function ($injector) {
    var Tag = $injector.get('Tag'); // Here is your tag

    ...    
}]);

Application.factory('Tag', ['Blog', function (Blog) {
    ...
}]);

编辑

事实证明,当前的方法是服务定位器模式的一个例子,即 IoC 反模式。

于 2013-10-14T20:05:12.417 回答
1

最后的手段:不鼓励

在我的情况下,以角度解决此类循环依赖问题的最佳方法是通过-broadcasts触发函数调用$rootScope。然后,其他服务可以收听此广播并对所需的函数调用做出反应。它可能不是最优雅的解决方案,但在服务之间的交互主要是单向的某些情况下,它可能是一个合理的替代方案。(请注意,这也允许仅通过回调将返回值传递回广播函数)


一个伪示例是:

angular.module('myApp').factory('service1', ["$rootScope",
  function($rootScope) {
    function func1() {
      // do something
    }
    $rootScope.$broadcast("callFunc2"); // calls func2 from service 1

    return {
      func1: func1
    }
  }
]);
angular.module('myApp').factory('service2', ["service1", "$rootScope",
  function(service1, $rootScope) {
    function func2() {
      // do something
    }
    service1.func1();  // calls func1 from service 2
    $rootScope.on("callFunc2", func2);
  }
]);
于 2017-01-24T10:25:03.050 回答