VUE3.0 をすぐに始める方法: 入って学習する
Nest はモジュール メカニズムを提供し、モジュール デコレーターでプロバイダー、インポート、エクスポート、プロバイダー コンストラクターを定義することで依存関係の挿入が完了し、アプリケーション全体の開発はモジュールツリー。フレームワーク自体の規約に従ってアプリケーションを直接起動しても全く問題ありません。しかし、私にとっては、フレームワークによって宣言される依存関係の挿入、制御の反転、モジュール、プロバイダー、メタデータ、関連するデコレーターなどについて、より明確かつ体系的に理解できていないように感じます。
- なぜ制御の反転が必要なのでしょうか?
- 依存性注入とは何ですか?
- デコレーターは何をする人ですか?
- モジュール (@Module) でのプロバイダー、インポート、エクスポートの実装原則は何ですか?
理解できそうだけど、最初からわかりやすく説明しましょう、はっきり説明できません。そこで、いくつか調べてみてこの記事を思いつきました。ここからはゼロから本文に入っていきます。
1.1 Express、Koa
言語とその技術コミュニティの開発プロセスは、木の根がゆっくりと枝に成長し、葉が茂るプロセスと同じように、下位の機能から上に向かって徐々に充実させ、発展させる必要があります。以前は、Express や Koa などの基本的な Web サービス フレームワークが Nodejs に登場していました。非常に基本的なサービス機能を提供できます。このようなフレームワークに基づいて、多数のミドルウェアとプラグインがコミュニティで生まれ始め、フレームワークに豊かなサービスを提供しました。アプリケーションの依存関係を整理し、柔軟で面倒なアプリケーションの足場を構築する必要があり、特定のワークロードも必要です。
開発の後半では、より効率的な制作とより統一されたルールを備えたいくつかのフレームワークが誕生し、新たな段階への扉を開きました。
1.2 EGGJとNESTJS
迅速な生産アプリケーションにより適応し、標準を統合し、箱から出して利用できるようにするために、EGGJ、NESTJ、Midwayなどのフレームワークが開発されました。このタイプのフレームワークは、基礎となるライフサイクルを実装することによって、アプリケーションの実装を汎用的で拡張可能なプロセスに抽象化します。アプリケーションをより簡単に実装するには、フレームワークが提供する構成メソッドに従うだけです。框架实现了程序的过程控制,而我们只需要在合适位置组装我们的零件就行,这看起来更像是流水线工作,每个流程被分割的很清楚,也省去了很多实现成本。
1.3 Summary
The above two stages are just a foreshadowing. We can roughly understand that the upgrade of the framework improves production efficiency. To achieve the upgrade of the framework, some design ideas and patterns will be introduced. Inversion of control appears in Nest. ,依存関係の注入とメタプログラミングの概念については、以下で説明します。
2.1 依存関係の注入
アプリケーションは実際には多数の抽象クラスで構成されており、それらが互いに呼び出し合うことでアプリケーションのすべての機能を実現します。アプリケーションのコードと関数が複雑になるにつれて、クラスの数が増え、クラス間の関係がますます複雑になるため、プロジェクトの保守は確実にますます困難になります。
たとえば、Koa を使用してアプリケーションを開発する場合、Koa 自体は主に一連の基本的な Web サービス機能を実装します。アプリケーションの実装プロセスでは、多くのクラス、インスタンス化メソッド、およびこれらのクラスの相互依存関係がすべて定義されます。コードロジック内で自由に編成および制御できます。各クラスのインスタンス化は手動で新しく行われ、クラスを 1 回だけインスタンス化して共有するか、それとも毎回インスタンス化するかを制御できます。次のクラス B は A に依存します。B がインスタンス化されるたびに、A も 1 回インスタンス化されるため、各インスタンス B に対して、A は共有されないインスタンスになります。
クラス A{} //B クラスB{ コンストラクタ(){ this.a = 新しい A(); }以下の C は取得した外部インスタンスなので
、
複数の C インスタンスが app.a インスタンスを共有します。
クラス A{} // c const アプリ = {}; app.a = 新しい A(); クラスC{ コンストラクタ(){ this.a = app.a; } }
次のDは、Constructorパラメーターを介して渡されます。または、共有アプリ(DおよびF Share App.A)に渡すことができます。これはパラメーターのパスになりました。また、Xクラスインスタンスを渡すこともできます。
クラス A{} クラスX {} // d const app = {}; app.a = new a(); クラスD{ コンストラクター(a){ this.a = a; } } クラスF{ コンストラクター(a){ this.a = a; } } 新しいD(app.a) 新しいf(app.a)
新しい
D(新しい
コンストラクターを介した注入 (値による受け渡し) は、実装メソッドの 1 つにすぎません。また、外部依存関係を内部依存関係に渡すことができる限り、set メソッド呼び出しまたはその他のメソッドを実装することによって渡すこともできます。それは本当に簡単です。
クラス A{} //D クラスD{ setDep(a){ this.a = a; } } const d = 新しい D() d.setDep(new A())
2.2 すべて依存性注入ですか?
反復が進むと、Bの依存関係は異なる前提条件に従って変化するように見えます。たとえば、前提条件 1 のthis.a
A のインスタンスに渡す必要があり、前提条件 2 のthis.a
X のインスタンスに渡す必要があります。この時点で、実際の抽象化を開始します。上記Dのような依存性注入メソッドに変換していきます。
初期には、アプリケーションを実装したとき、この部分では、この部分が繰り返された後、クラスBとCの執筆方法を実装しましたコードの部分は必ずしも触れられるわけではありません。後々の拡張を考慮すると開発効率に影響し、役に立たない可能性があります。そのため、ほとんどの場合、抽象化が必要なシナリオに遭遇し、コードの一部を抽象的に変換します。
// class B{ 変換前 コンストラクタ(){ this.a = 新しい A(); } } 新しいb() //クラス D{ 変換後 コンストラクター(a){ this.a = a; } } 新しいd(new A())新しい D
(
新しい実装コスト。
この例は、制約や規制のない開発モデルでの例を示すために示しています。さまざまなクラス間の依存関係を制御するコードを自由に書くことができます。完全にオープンな環境で、とても自由な焼畑農業の原始時代です。固定されたコード開発モデルや最高のアクション プランがないため、異なる開発者が介入したり、同じ開発者が異なる時点でコードを作成したりするため、コードが大きくなるにつれて依存関係が大きく異なり、共有インスタンスが複数回インスタンス化される可能性があることは明らかです。 、メモリを無駄にします。コードから完全な依存関係構造を確認することは難しく、コードの保守が非常に困難になる可能性があります。
そして、クラスを定義するたびに依存性注入の方法に従って記述し、Dのように記述します。すると、CとBの抽象化処理が進み、後の拡張が便利になり、変換のコストが削減されます。つまり、すべてのAll in 依赖注入
関係は依存関係注入を通じて実装されます。
ただし、初期の実装コストが再び高くなり、追加の実装コストがかからない可能性があるため、最終的には実装が失敗する可能性があります。必ず利益をもたらします。
2
。定義した依存関係の構成と依存関係の共有は、クラス管理の実現に役立ちます。この設計パターンは制御の反転と呼ばれます。
制御の反転は、初めて聞くと理解するのが難しいかもしれません。制御とは何を意味しますか?何が反転しましたか?
これは、開発者が最初からそのようなフレームワークを使用しており、最後の「エクスプレスとコア時代」を経験しておらず、古い社会の暴行を欠いているためであると推測されています。逆の文言と相まって、プログラムは非常に抽象的で理解しにくいように見えます。
前述したように、KOAアプリケーションを実装するとき、すべてのクラスは私たちによって完全に制御されるため、従来のプログラム制御方法と見なすことができます。 NESTを使用します。これは、実際の開発プロセス中に契約に従って構成コードを記述する必要があります。制御の反転。
本質は、プログラムの実装プロセスを統一された管理のためのフレームワークプログラムに引き渡し、開発者からフレームワークプログラムに制御力を譲渡することです。
正転の制御: 開発者の純粋な手動制御プログラム
制御の反転: フレームワーク プログラム制御
実例を挙げると、ある人が自分で車で通勤し、その目的は会社に行くことです。それはそれ自体を駆動し、独自のルートを制御します。そして、運転を引き継いでバスに乗れば、会社に行くために対応するシャトルバスを選択するだけで済みます。コントロールだけで、人々はどのバスを奪うかを覚えているだけで、人々はよりリラックスしています。バスシステムはコントローラーであり、バスラインは合意された構成です。
上記の実際の比較を通して、私はコントロールの反転を理解できるはずだと思います。
2.4 概要
Koa から Nest、フロントエンド JQuery から Vue React まで。実際、それらはすべて、前の時代の非効率性の問題を解決するために、フレームワークのカプセル化の段階的に実装されています。
上記のKOAアプリケーション開発は、非常に原始的な依存関係とインスタンス化を制御しますコントローラー、それらはすべて制御の反転と呼ばれることができます。これも私の個人的な理解ですが、何か問題があれば神様が指摘してくださると幸いです。
Nest のモジュール @Module について話しましょう。依存関係の注入と制御の反転には、これがメディアとして必要です。
Nestjsは、制御の反転を実装し、モジュール(@module)のインポート、エクスポート、およびプロバイダーを構成してプロバイダーを管理することに同意します。これはクラスの依存関係です。
プロバイダーは、現在のモジュールに登録され、Bが現在のモジュールに参照されている場合、クラスをインスタンス化することができます。
import { モジュール } から '@nestjs/common'; import { ModuleX } from './moduleX'; './a'から{a}をインポートします。 './B'から{b}をインポートします。 @module({ インポート:[modulex]、 プロバイダー:[a、b]、 エクスポート:[a] }) エクスポートクラスモジュール{} // b クラスB { コンストラクター(a:a){ this.a = a; }エクスポートとは
、
exports
のモジュールのproviders
で、外部モジュールで共有できるクラスとしてインスタンス化されたクラスを指します。たとえば、ModuleF の C クラスがインスタンス化されるときに、ModuleD の A クラスのインスタンスを直接注入したいとします。 ModuleD でエクスポート A を設定し、ModuleF のimports
を通じて ModuleD をインポートするだけです。
以下の記述方法に従って、制御プログラムの反転により依存関係が自動的にスキャンされます。まず、自分のモジュールのプロバイダーにプロバイダー A があるかどうかを確認します。存在しない場合は、インポートされた ModuleD で A のインスタンスを探します。測定されたインスタンスがcインスタンスに注入されます。
'@nestjs/common'から{module}をインポートします。 './moduled'から{moduled}をインポートします。 './C'から{c}をインポートします。 @module({ 輸入:[モジュール]、 プロバイダー:[c]、 }) class modulefをエクスポート{} // c クラスC { コンストラクター(a:A){ this.a = a; } }
したがって、外部モジュールに現在のモジュールのクラスインスタンスを使用する場合は、最初に現在のモジュールのproviders
のインスタンス化クラスを定義し、次にこのクラスを定義およびエクスポートする必要があります。そうしないと、エラーが報告されます。
// @Module を修正します({ プロバイダー: [A]、 エクスポート:[a] }) //エラー@module({ プロバイダー: []、 エクスポート:[a] })
モジュールは後の補足
モジュールのインスタンスを見つけるプロセスを振り返ると、それは実際には少し不明です。コアポイントは、プロバイダーのクラスがインスタンス化され、インスタンス化された後、プロバイダーのクラスのみがインスタンス化され、エクスポートとインポートは単なる組織関係構成です。
、独自
のプロバイダーを使用しています
。
コンストラクター(プライベートA:a){ } }
TypeScriptは、Constructorパラメーター(プライベート、保護、パブリック、リードリー)をサポートしているため、クラス属性(パラメータープロパティ)として暗黙的かつ自動的に定義されるため、 this.a = a
使用する必要はありません。 Nest ではこのように書かれています。
メタプログラムの概念は、コントロールとデコレーターの反転に反映されています。メタプログラムの本質はまだプログラミングであることが大まかに理解できますが、この抽象プログラムは、実際には他のものを使用できる拡張機能であるメタデータ(@moduleのオブジェクトデータなど)を識別できます。データとしてのプログラム。このような抽象的なプログラムを書くとき、メタプログラムです。
4.1メタ
データは、メタデータの概念によく言及されています。絡み合っています。
メタデータの定義は次のとおりです。データ、主にデータ属性を説明する情報を記述するデータ、プログラムを説明するデータとして理解することもできます。
nestの @moduleによって構成されたexports、providers、imports、controllers
すべてメタデータです。これは、このデータ情報がエンドユーザーに表示される実際のデータではなく、読み取りおよび認識されているために使用されるためです。フレームワークプログラム。
4.2巣のデコレーター
Nestのデコレーターソースコードを見ると、ほとんどすべてのデコレーター自体が反射メタデータを介してメタデータのみを定義していることがわかります。
@Injectableデコレーター
エクスポート関数注射可能(オプション?:InjectableOptions):classdecorator { return(ターゲット:オブジェクト)=> { refrect.definemetadata(injectable_watermark、true、ターゲット); resprem.definemetadata(scope_options_metadata、options、ターゲット); }; }
ここにはproviders
providers
はproviders
簡単に理解できます。フレームワークプログラムで自動的に使用され、開発者はインスタンス化と依存関係を明示的に実行する必要はありません。クラスは、モジュールにインスタンス化された後にのみプロバイダーになります。 providers
のクラスは反射し、プロバイダーになります。
別の例は、データベースのORM(オブジェクトリレーショナルマッピング)です。ORMを使用するには、テーブルフィールドを定義するだけで、ORMライブラリはオブジェクトデータをSQLステートメントに自動的に変換します。
const data = tablemodel.build(); data.time = 1; data.Browser = 'Chrome'; data.save(); // sql:tablenameに挿入(time、browser)[{"time":1、 "browser": "chrome"}]
ORMライブラリはリフレクションテクノロジーを使用しているため、ユーザーはフィールドデータ自体に注意を払う必要があります。オブジェクトはORMライブラリリフレクションがSQL実行ステートメントになります。
4.3反射メタデータ
リフレクトメタデータは、ネストがメタデータを管理するために使用する反射ライブラリです。 Reflect-MetadataはWeakMapを使用してグローバルな単一インスタンスを作成し、セットを介して装飾されたオブジェクト(クラス、方法など)のメタデータをセットおよび取得し、メソッドを取得します。
// var _weakmap =!usepolyfill && typeof weakmap === "function"? var metadata = new _weakmap(); 関数definemetadata(){ 普通defineOwnmetadata(){ getorcreatemetadatamap(){ var targetmetadata = metadata.get(o); if(isundefined(targetmetadata)){ if(!create) 未定義を返します。 TargetMetadata = new _map(); Metadata.set(O、TargetMetadata); } var metadatamap = targetmetadata.get(p); if(isundefined(metadatamap)){ if(!create) 未定義を返します。 metadatamap = new _map(); TargetMetadata.set(P、Metadatamap); } メタデータを返します。 } } }
反射メタデータは、統一された管理のためにグローバルなシングルトンオブジェクトに装飾された人のメタデータを保存します。 Reflect-Metadataは特定の反射を実装していませんが、反射実装を支援するツールライブラリを提供します。
、前の質問を見てみましょう。
制御の反転が必要なのはなぜですか?
依存性注入とは何ですか?
デコレーターは何をしますか?
モジュール(@module)のプロバイダー、輸入、およびエクスポートの実装原則は何ですか?
1と2私はそれがまだ少し曖昧であれば、あなたがそれをもう一度読んで、別の著者の考えを通して知識を理解するのに役立つことをお勧めします。
5.1問題[3 4]概要:
Nestは反射技術を使用して制御の反転を実装し、メタプログラム機能を提供します。オブジェクト(Reflect-Metadataライブラリを使用)。プログラムが実行された後、Nest Framework内の制御プログラムはモジュールツリーを読み取り、登録し、メタデータをスキャンしてクラスをインスタンス化してプロバイダーになり、プロバイダー Imports Exports定義に従ってすべてのモジュールで提供します。 。
この記事には多くの概念があり、詳細な分析はゆっくりと理解されていない場合は、時間がかかります。さて、この記事はまだ多くの努力をしました。