UFO ET IT

AngularJS의 순환 종속성 및 OOP 문제

ufoet 2020. 12. 11. 19:03
반응형

AngularJS의 순환 종속성 및 OOP 문제


AngularJS + OOP는 사용하기에 좀 섹시한 기능입니다.

안녕하세요, 저는 이미 한동안 AngularJs와 함께 OOP를 성공적으로 사용하고 있습니다 (처음 에는 oop 상속이 작동 하는 angularjs로 시작됨 ), 제공된 접근 방식을 사용하면 클래스를 각도 서비스로 정의 할 수 있으며 나중에 다음과 같이 확장하거나 상속 할 수 있습니다.

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

플 런커 : http://plnkr.co/edit/rAtVGAsNYggBhNADMeoT

설명 된 접근 방식을 사용하면 각 인프라에 아름답게 통합되는 클래스를 정의 할 수 있습니다. OOP와 AngularJ라는 두 가지 세계에서 온갖 멋진 기능을 얻을 수 있습니다. 종속성 주입은 클래스에 대해 무료이며 클래스를 단순하게 만들고 나중에 재사용 할 수있는 일부 기본 클래스에 많은 상용구 컨트롤러 코드를 넣을 수 있습니다.

하나

AngularJs 인프라는 이전에 설명한 접근 방식이 100 % 확산되는 것을 차단합니다. 당신이 (즉, 재귀 집계) 재귀 클래스 정의를 정의 할 때 문제가 발생하면 같은 두 개의 클래스 정의가 있다고 가정 Blog하고Tag

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

Blog둘 다 Tag자체 참조로 인해 순환 종속성이 발생 하기 때문에 작동하지 않습니다 .

추신

마지막으로, 특정 경우에 내 문제를 해결하지만 일반적으로 작동하지 않는 추악한 해결책을 찾았으며 내가 말했듯이 예쁘지 않습니다.

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

질문

네임 스페이스가 순환 종속성의 대상 일 수 있으므로 위의 수정은 작동하지 않습니다. 이것은 설명 된 문제에 대한 해결책이 아니라 현재 한 단계 더 깊은 문제를 의미합니다.

일반적인 경우에 설명 된 문제를 해결하는 방법에 대한 제안이 있습니까?


A circular dependency is always the sign of mixing of concerns, which is a really bad thing. Miško Hevery, one of the authors of AngularJS, explains a nice solution on his awesome blog. In short, you probably have a third service hidden somewhere, which is the only part of your code really needed by the two others.


I'm answering my own question just because I've found a technical way of resolving the issue that I have originally posted about. But before that, I strongly encourage you to use Blackhole's suggestion since it allows solving a broader set of problems which are usually caused by bad architecture. Please prefer using his approach first, and return to current one in case that you know what you are doing.

So here goes:

You can use $injector service and inject required definitions at run-time, which is legal from technical point of view, but again according to this post (hard to imagine that it is written in 2008), this is like a black magic, do that and it will strike you back:

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

    ...    
}]);

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

Edit

It turned out that current approach is an example of Service Locator pattern, which is IoC Antipattern.


LAST RESORT: NOT ENCOURAGED

In my case the best way to get around a circular-dependency-problem like this in angular, is to trigger function-calls via $rootScope-broadcasts. The other service can then listen to this broadcast and react with the desired function-call. It may not be the most elegant solution but in some cases where the interaction between the services is mainly one-directional anyways, it may be a reasonable alternative. (note that this also allows return-values to be passed back to the broadcasting function via callbacks only)


A pseudo-example of this would be:

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

참고URL : https://stackoverflow.com/questions/19344214/problems-with-circular-dependency-and-oop-in-angularjs

반응형