5分間でJavaScriptのIoCを把握します.


IoC,制御反転(Inversion of Control).逆さまの原則(Dependence Inversion Principle)に依存している一つのインプリメンテーションです.つまりインターフェースに向かってプログラミングします.IoCの実現は、第三者の容器を介して、依存関係のあるオブジェクトを結合し、開発・維持コストを低減することができる.
次に我々は完全な例を通してこれらの概念をさらに理解する.
急を要する業務モジュール
まず、例を見てみましょう.
class Order{
    constructor(){}
    getInfo(){
        console.log('      ')
    }
}

let order = new Order('   ');
order.getInfo()
上記のコードはあるシステムの注文管理モジュールで、現在の機能は注文情報を出力することです.
注文モジュールに評価機能を追加する
業務の発展に伴い、注文書に評価機能を追加する必要があります.
とても簡単な需要ですよね?既存のコードを少し修正し、評価モジュールを追加すればいいです.
class Rate{
    star(stars){
        console.log('        %s ',stars);
    }
}
class Order{
    constructor(){
        this.rate = new Rate();
    }
    //          ...
}

let order = new Order('   ');
order.getInfo();
order.rate.star(5);
小さな変更だけで、簡単に実現しました.評価モジュールを追加して、注文モジュールに依存して導入すればいいです.もうすぐQAテストもパスします.コーヒーを一杯してお祝いしましょう.☕️
モジュールに共有機能を追加
カップを持ち上げたところ、IM上の製品のクラスメートの顔が明るくなりました.
PM:注文書とコメントを友達圏などに共有できれば、xxxxは大幅にアップします.
RD:はい、調べてみます.
採点モジュールを追加したばかりです.モジュールを共有しても大丈夫です.
class Rate(){ /**         */}

class Share(){
    shareTo(platform){
        switch (platform) {
            case 'wxfriend':
                console.log('       ');
                break;
            case 'wxposts':
                console.log('        ');
                break;
            case 'weibo':
                console.log('     ');
                break;
            default:
                console.error('    ,   platform');
                break;
        }
    }
}

class Order{
    constructor(){
        this.rate = new Rate();
        this.share = new Share();
    }
    //          ...
}

const order = new Order();
order.share.shareTo('wxposts');
今回も共有モジュールを追加して注文モジュールに導入します.運転リスト測定を再作成した後、次にQAはShareモジュールをテストし、Orderモジュールを回帰テストします.
ちょっと調子が悪いようです.予測できるのは、注文のこのモジュールは私達の製品のライフサイクルの中でまだ初期にあって、後で彼の拡張/アップグレードあるいはメンテナンスに対してとても頻繁なことです.毎回メインモジュールとモジュールを修正すれば、需要を満たすことができますが、開発とテストには十分友好的ではありません.ダブルのシングルテストが必要です.
IoCを使った思想改造モジュール
名前の通り、IoCの主な行為はモジュールの制御権を逆さまにすることです.上記の例では、Orderを高レベルモジュールと呼び、RateおよびShareを低層モジュールと呼ぶ.トップモジュールでは、下位モジュールに依存します.IoCはこの依存関係を逆さまにします.トップモジュールはインターフェースを定義し、下位モジュールはインターフェースを実現します.このように、低層モジュールを修正したり追加したりすると、開閉原則を破壊しません.その実現方法は通常、注入に依存する.すなわち、依存する低層モジュールを高レベルモジュールに注入することである.
上位モジュールに静的属性を定義して依存関係を維持する.
class Order {
    //          Map
    static modules = new Map();
    constructor(){
        for (let module of Order.modules.values()) {
            //     init  
            module.init(this);
        }
    }
    //      Map     
    static inject(module) {
        Order.modules.set(module.constructor.name, module);
    }
    /**       */
}

class Rate{
    init(order) {
        order.rate = this;
    }
    star(stars){
        console.log('        %s ',stars);
    }
}

const rate = new Rate();
//     
Order.inject(rate);
const order = new Order();
order.rate.star(4); 
上記の例では、Orderクラスで自分の依存モジュールを維持することによって、モジュール内でinit方法を実現し、構造関数初期化時にOrderを呼び出す.このときOrderは容器と呼ぶことができ、彼は依存関係を懐に収める.
IoCを再理解する
注文モジュールの改造を完了しました.振り返ってIoCを見ます.
依存注入とは、高レベル依存性に影響しない低レベルのモジュールをパラメータで注入することである.
しかし、注入の方式は注意してください.高レベルモジュールの中で、依存しているすべての低レベルモジュールをあらかじめ知っておくことはできないし、高レベルモジュールの中で、低レベルモジュールの具体的な実現に依存してはいけないからです.
したがって、注入は2つの部分に分ける必要があります.高レベルモジュールにおいてキャリア機構を通して低レベルモジュールに対する依存性を分離し、低レベルモジュールの抽象に依存します.低レベルモジュールの実装は、所定の抽象的な実装に従っており、インジェクタによって高レベルモジュールに依存します.
このように高いレベルのモジュールは業務ロジックを逸脱して低レベルのモジュールの容器になりますが、低レベルのモジュールはインターフェースに向かってプログラミングします.これは制御反転である.注入依存により制御権を依存する低レベルモジュールに渡す.
より簡潔で効率的なIoC実現
上記の例では、IoCの実装は、モジュールは明示的な宣言init方法を必要とし、容器は注入依存性を表示し、初期化する必要がある.これらの業務に関係のない内容は基本類、サブクラスにカプセル化して継承することによって最適化できます.また、修飾器法によって簡略化することもできます.
修飾器(Decocorators)は、私たちのクラスの声明とメンバーのために、元编程文法によって表示を追加する方法を提供します.Javascriptの中の修飾器は現在提案募集の第二段階にありますが、Type Scriptの中で実験的な特性として支持されています.
次に、IoCの実現方法を重点的に紹介します.
クラス修飾器で注入する
以下の例のコードはすべてType Scriptです.
まず、低レベルモジュールを実現します.これらのモジュールは自分の業務ロジックだけを処理します.他に注目する必要はありません.

class Aftermarket {
    repair() {
        console.log('         ');
    }
}

class Rate {
    star(stars: string) {
        console.log(`   ${stars} `);
    }
}

class Share {
    shareTo(platform: string) {
        switch (platform) {
            case 'wxfriend':
                console.log('       ');
                break;
            case 'wxposts':
                console.log('        ');
                break;
            case 'weibo':
                console.log('     ');
                break;
            default:
                console.error('    ,   platform');
                break;
        }
    }
}
次に,実用化に依存する低層モジュール用のクラス修飾器を実現し,容器に注入する.
function Inject(modules: any) {
    return function(target: any) {
        modules.forEach((module:any) => {
            target.prototype[module.name] = new module();
        });
    };
}
最後に容器類にこの修飾器を使います.
@Inject([Aftermarket,Share,Rate])
class Order {
    constructor() {}
    /**       */
}

const order:any = new Order();
order.Share.shareTo('facebook');
属性修飾器を使って実現Ursajsでは、注入依存性を達成するために属性修飾器を使用する.Ursajsは、@Resource修飾器および@Inject修飾器を提供する.@Resourceはクラス修飾器であり、その修飾されたクラスの例はUrsajsIoC に注入される.
@Resource()
class Share{}
@Injectは属性修飾器であり、クラスでは@Resourceによって修飾されたクラスのインスタンスを指定変数に注入することができる.
class Order{
    @Inject('share')
    share:Share;
    /**       */
}
また、簡潔で優雅なフレームワークとして、Ursajsはアドレス指定最適化を内蔵しており、より効率的にリソースを取得することができる.
銀弾はありません
IoCは非常に強力ですが、それはまだデザイン思想だけで、いくつかのシーンでの解決策の洗練されています.すべての高結合がもたらす問題を解決することはできないし、不可能です.開発者として、どのシーンがどのようなプランに適しているかを識別する必要があります.
結び目
  • 複合システムにおける高結合は、開発維持コストが高くなることをもたらす.
  • IoCは、容器を介してデカップリングを実現し、システムの複雑度を低減する
  • .
  • 装飾器はIoCをより簡潔で効率的に実現する.
  • 銀弾がありません.
    参照
  • tslang-decorators
  • Ursajs-依存注入
  • ️R.I.P.