簡體   English   中英

AngularJS 中循環依賴和 OOP 的問題

[英]Problems with circular dependency and OOP in AngularJS

AngularJS + OOP 是一種使用起來很性感的特性

嗨,我已經成功地將 OOP 與 AngularJs 一起使用了一段時間(首先從angularjs開始, 在操作中使用 oop 繼承),提供的方法允許您將類定義為 angular 服務,以后您可以像這樣擴展或繼承:

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
    };
}]);

上述修復將不起作用,因為命名空間也可能是循環依賴的主題。 這意味着它不是所描述問題的解決方案,而是現在更深一層的問題。

關於如何在一般情況下解決所描述的問題的任何建議?

循環依賴始終是關注混合的標志,這是一件非常糟糕的事情。 Miško Hevery 是 AngularJS 的作者之一, 在他很棒的博客中解釋了一個很好的解決方案。 簡而言之,您可能在某處隱藏了第三個服務,這是其他兩個服務真正需要的代碼的唯一部分。

我回答我自己的問題只是因為我找到了解決我最初發布的問題的技術方法。 但在此之前,我強烈建議您使用 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 反模式。

最后的手段:不鼓勵

在我的情況下,在 angular 中解決這樣的循環依賴問題的最佳方法是通過$rootScope -broadcasts 觸發函數調用 然后,其他服務可以收聽此廣播並響應所需的函數調用。 它可能不是最優雅的解決方案,但在某些服務之間的交互主要是單向的情況下,它可能是一個合理的選擇。 (請注意,這也允許僅通過回調將返回值傳遞回廣播函數)


一個偽示例是:

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);
  }
]);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM