62

AngularJS + OOP はちょっとセクシーな機能です

こんにちは、私は既にしばらくの間 AngularJs で OOP をうまく使用しています (最初は oop 継承が動作している angularjsから始めました)。提供されたアプローチにより、クラスを 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;
}]);

プランカー: http://plnkr.co/edit/rAtVGAsNYggBhNADMeoT

説明したアプローチを使用すると、Angular インフラストラクチャに美しく統合するクラスを定義できます。OOP と AngularJs という 2 つの世界からあらゆる種類の気の利いた機能を利用できます。依存性注入はクラスに対して無料であり、クラスをシンプルにし、後で再利用できる基本クラスに多くのボイラープレート コントローラー コードを配置できます。

でも

AngularJs インフラストラクチャは、前述のアプローチをすべて 100% に広げることをブロックします。この問題は、再帰的なクラス定義 (つまり、再帰的な集約) を定義しようとすると発生します。たとえば、 と のような 2 つのクラス定義がある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が自己参照しているため、循環依存関係が発生しているため、機能しません。

PS

最後に、特定のケースで私の問題を解決するちょっとい解決策を見つけましたが、一般的には機能しません。私が言ったように、それはきれいではありません:

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

質問

名前空間も循環依存の対象になる可能性があるため、上記の修正は機能しません。これは、説明されている問題の解決策ではなく、1 レベル深い問題であることを意味します。

一般的なケースで説明されている問題を解決する方法について何か提案はありますか?

4

3 に答える 3

70

循環依存は常に懸念の混合の兆候であり、これは非常に悪いことです。AngularJS の作成者の 1 人である Miško Hevery は、素晴らしいブログ で優れたソリューションを説明しています。つまり、他の 2 つのサービスが本当に必要としているコードの唯一の部分である 3 つ目のサービスがどこかに隠されている可能性があります。

于 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 Antipattern である Service Locator パターンの一例であることが判明しました。

于 2013-10-14T20:05:12.417 に答える