Cara cepat memulai VUE3.0: Masuk dan pelajari
Nest menyediakan mekanisme modul. Injeksi ketergantungan diselesaikan dengan menentukan penyedia, impor, ekspor, dan konstruktor penyedia di dekorator modul, dan pengembangan seluruh aplikasi diatur melalui dekorator modul. pohon modul. Sama sekali tidak ada masalah dalam meluncurkan aplikasi secara langsung sesuai dengan konvensi framework itu sendiri. Namun, bagi saya, saya merasa kurang memiliki pemahaman yang lebih jelas dan sistematis tentang injeksi ketergantungan, inversi kontrol, modul, penyedia, metadata, dekorator terkait, dll. yang dinyatakan oleh kerangka kerja.
- Mengapa inversi kendali diperlukan?
- Apa itu injeksi ketergantungan?
- Apa yang dilakukan dekorator?
- Apa prinsip implementasi penyedia, impor, dan ekspor dalam modul (@Module)?
Sepertinya saya bisa memahami dan mengapresiasinya, tapi biar saya jelaskan dari awal, saya tidak bisa menjelaskannya dengan jelas. Jadi saya melakukan riset dan menghasilkan artikel ini. Mulai sekarang, kita mulai dari awal dan memasukkan teks utama.
1.1 Ekspres, Koa
Proses perkembangan suatu bahasa dan komunitas teknisnya harus secara bertahap memperkaya dan berkembang dari fungsi paling bawah ke atas, seperti proses akar pohon yang perlahan tumbuh menjadi cabang dan kemudian penuh daun. Sebelumnya, kerangka layanan web dasar seperti Express dan Koa muncul di Nodejs. Mampu memberikan kemampuan pelayanan yang sangat mendasar. Berdasarkan kerangka kerja seperti itu, sejumlah besar middleware dan plug-in mulai lahir di komunitas, memberikan layanan yang lebih kaya untuk kerangka tersebut. Kita perlu mengatur dependensi aplikasi dan membangun scaffolding aplikasi sendiri, yang fleksibel dan rumit, serta memerlukan beban kerja tertentu.
Kemudian dalam pengembangan, lahirlah beberapa kerangka kerja dengan produksi yang lebih efisien dan aturan yang lebih terpadu, yang mengantarkan pada tahap yang lebih baru.
1.2 EggJs dan Nestjs
Agar lebih mudah beradaptasi dengan aplikasi produksi cepat, menyatukan standar dan membuatnya tersedia secara langsung, kerangka kerja seperti EggJs, NestJs, dan Midway telah dikembangkan. Kerangka kerja jenis ini mengabstraksi implementasi aplikasi menjadi proses universal dan dapat diperluas dengan menerapkan siklus hidup yang mendasarinya. Kita hanya perlu mengikuti metode konfigurasi yang disediakan oleh kerangka kerja untuk mengimplementasikan aplikasi dengan lebih sederhana. Kerangka kerja ini menerapkan kontrol proses pada program, dan kita hanya perlu merakit bagian-bagian kita di lokasi yang sesuai. Ini lebih terlihat seperti pekerjaan jalur perakitan dengan jelas, dan banyak biaya implementasi yang dihemat.
1.3 Ringkasan
Dua tahap di atas hanyalah gambaran saja. Secara kasar kita dapat memahami bahwa peningkatan kerangka kerja meningkatkan efisiensi produksi. Untuk mencapai peningkatan kerangka kerja, beberapa ide dan pola desain akan diperkenalkan di Nest. injeksi ketergantungan, dan konsep metaprogramming, mari kita bahas di bawah ini.
2.1 Injeksi Ketergantungan
Sebuah aplikasi sebenarnya adalah sekumpulan kelas abstrak, yang merealisasikan semua fungsi aplikasi dengan saling memanggil. Dengan meningkatnya kompleksitas kode aplikasi dan fungsi, proyek pasti akan menjadi semakin sulit untuk dipelihara karena semakin banyak kelas dan hubungan di antara mereka menjadi semakin kompleks.
Misalnya, jika kita menggunakan Koa untuk mengembangkan aplikasi kita, Koa sendiri terutama mengimplementasikan serangkaian kemampuan dasar layanan Web. Dalam proses implementasi aplikasi, kita akan mendefinisikan banyak kelas, metode instantiasi, dan saling ketergantungan dari kelas-kelas ini. diatur dan dikontrol secara bebas oleh kami dalam logika kode. Instansiasi setiap kelas baru kami lakukan secara manual, dan kami dapat mengontrol apakah suatu kelas hanya dibuat instance-nya satu kali lalu dibagikan, atau apakah dibuat instance-nya setiap saat. Kelas B berikutnya bergantung pada A. Setiap kali B dipakai, A akan dipakai satu kali, jadi untuk setiap instance B, A adalah instance yang tidak dibagikan.
kelas A{} // B kelas B{ konstruktor(){ ini.a = baru A(); } }
C di bawah ini adalah instance eksternal yang diperoleh, jadi beberapa instance C berbagi instance app.a.
kelas A{} // C aplikasi const = {}; app.a = A baru(); kelas C{ konstruktor(){ this.a = aplikasi.a; } }
D berikut diteruskan melalui parameter konstruktor. Anda dapat meneruskan instance yang tidak dibagikan setiap kali, atau Anda dapat meneruskan instance aplikasi bersama (D dan F berbagi aplikasi.a), dan karena caranya. sekarang menjadi parameter Lulus, saya juga bisa meneruskan instance kelas X.
kelas A{} kelas X{} //D aplikasi const = {}; app.a = A baru(); kelas D{ konstruktor(a){ ini.a = a; } } kelas F{ konstruktor(a){ ini.a = a; } } D baru (aplikasi.a) F baru (aplikasi a)
baru
D (baru
Injeksi melalui konstruktor (melewati nilai) hanyalah salah satu metode implementasi. Itu juga dapat diteruskan dengan mengimplementasikan pemanggilan metode set, atau metode lainnya, selama ketergantungan eksternal dapat diteruskan ke internal. Sesederhana itu.
kelas A{} //D kelas D{ setDep(a){ ini.a = a; } } konstanta d = baru D() d.setDep(new A())
2.2 Semua dalam injeksi ketergantungan?
Saat iterasi berlangsung, tampak bahwa ketergantungan B akan berubah sesuai dengan prasyarat yang berbeda. Misalnya, prasyarat satu this.a
harus diteruskan pada instance A, dan prasyarat dua this.a
harus diteruskan pada instance X. Saat ini, kita akan mulai melakukan abstraksi sebenarnya. Kami akan mengubahnya menjadi metode injeksi ketergantungan seperti D di atas.
Pada awal-awal implementasi aplikasi, kami akan mengimplementasikan metode penulisan kelas B dan C asalkan memenuhi kebutuhan saat itu. Hal ini sendiri tidak menjadi masalah setelah proyek diulang selama beberapa tahun kode belum tentu disentuh. Jika kita mempertimbangkan perluasan di kemudian hari, hal itu akan mempengaruhi efisiensi pembangunan dan mungkin tidak berguna. Jadi sering kali, kita menghadapi skenario yang memerlukan abstraksi, dan kemudian mengubah sebagian kode secara abstrak.
// kelas B{ sebelum transformasi konstruktor(){ ini.a = baru A(); } } B baru() //Kelas D{ setelah transformasi konstruktor(a){ ini.a = a; } } D baru(A baru())D baru
(biaya implementasi
baru.
Contoh ini diberikan di sini untuk menggambarkan bahwa dalam model pembangunan tanpa batasan atau peraturan apa pun. Kita dapat dengan bebas menulis kode untuk mengontrol ketergantungan antar berbagai kelas. Di lingkungan yang benar-benar terbuka, kondisinya sangat bebas. Ini adalah era primitif pertanian tebang-dan-bakar. Karena tidak ada model pengembangan kode yang tetap dan tidak ada rencana tindakan tertinggi, karena pengembang yang berbeda melakukan intervensi atau pengembang yang sama menulis kode pada waktu yang berbeda, hubungan ketergantungan akan menjadi sangat berbeda seiring dengan pertumbuhan kode. Jelasnya, instance bersama dapat dibuat berkali-kali , membuang-buang memori. Dari kode tersebut, sulit untuk melihat struktur ketergantungan yang lengkap, dan kode tersebut mungkin menjadi sangat sulit untuk dipelihara.
Kemudian setiap kali kita mendefinisikan sebuah kelas, kita menulisnya sesuai dengan metode injeksi ketergantungan, dan menulisnya seperti D. Kemudian proses abstraksi C dan B ditingkatkan, yang membuat perluasan selanjutnya lebih mudah dan mengurangi biaya transformasi. Jadi ini disebut All in 依赖注入
, artinya semua dependensi kita diimplementasikan melalui dependency injection.
Namun, biaya implementasi awal menjadi tinggi lagi, dan sulit untuk mencapai kesatuan dan ketekunan dalam kolaborasi tim. Pada akhirnya, implementasi mungkin gagal. Hal ini juga dapat didefinisikan sebagai desain yang berlebihan, karena tambahan biaya implementasi mungkin tidak tentu dapat dicapai.
2.3 Inversi Kontrol
Sekarang kita telah menyetujui penggunaan injeksi ketergantungan secara terpadu, dapatkah kita mengimplementasikan pengontrol tingkat bawah melalui enkapsulasi yang mendasari kerangka kerja dan menyetujui aturan konfigurasi ketergantungan? konfigurasi ketergantungan yang kami tetapkan dan berbagi ketergantungan untuk membantu kami mencapai pengelolaan kelas. Pola desain ini disebut inversi kendali .
Pembalikan kendali mungkin sulit dipahami saat pertama kali mendengarnya. Apa yang dimaksud dengan kendali? Apa yang dibalik?
Ada spekulasi bahwa hal ini terjadi karena pengembang telah menggunakan kerangka kerja seperti itu sejak awal dan belum mengalami "era Ekspres dan Koa" yang terakhir dan tidak memiliki pengaruh dari masyarakat lama. Ditambah dengan susunan kata yang terbalik, program ini tampak sangat abstrak dan sulit dipahami.
Seperti yang telah kami sebutkan sebelumnya, ketika mengimplementasikan aplikasi Koa, semua kelas dikontrol sepenuhnya oleh kami, sehingga dapat dikatakan sebagai metode kontrol program konvensional, maka kami menyebutnya: kontrol rotasi maju. Kami menggunakan Nest, yang mengimplementasikan sekumpulan pengontrol di bagian bawah. Kami hanya perlu menulis kode konfigurasi sesuai kesepakatan selama proses pengembangan sebenarnya, dan program kerangka kerja akan membantu kami mengelola injeksi ketergantungan kelas, jadi kami menyebutnya: inversi kendali.
Intinya adalah menyerahkan proses implementasi program ke program kerangka untuk pengelolaan terpadu, dan mengalihkan kekuasaan kendali dari pengembang ke program kerangka.
Kontrol rotasi maju: program kontrol manual murni milik pengembang
Pembalikan kontrol: kerangka kontrol program
Sebagai contoh nyata, seseorang berkendara ke tempat kerja sendiri, dan tujuannya adalah untuk mencapai perusahaan. Ia mengemudi sendiri dan mengendalikan rutenya sendiri. Dan jika dia menyerahkan kendali mengemudi dan naik bus, dia hanya perlu memilih shuttle bus yang sesuai untuk mencapai perusahaan. Dari segi kendali saja, masyarakat sudah terbebaskan. Mereka hanya perlu mengingat bus mana yang harus diambil. Sistem bus adalah pengontrolnya, dan jalur bus adalah konfigurasi yang disepakati.
Melalui perbandingan aktual di atas, saya rasa saya seharusnya bisa memahami inversi kendali.
2.4 Ringkasan
Dari Koa hingga Nest, dari front-end JQuery hingga Vue React. Faktanya, semuanya diterapkan selangkah demi selangkah melalui enkapsulasi kerangka kerja untuk menyelesaikan permasalahan inefisiensi di era sebelumnya.
Pengembangan aplikasi Koa di atas menggunakan cara yang sangat primitif untuk mengontrol dependensi dan instantiasi, yang mirip dengan dom operasi JQuery di front end. Cara yang sangat primitif ini disebut penerusan kontrol, dan Vue React seperti yang disediakan oleh Nest pengontrol, semuanya dapat disebut inversi kendali. Ini juga pemahaman pribadi saya. Jika ada masalah, saya berharap Tuhan menunjukkannya.
Mari kita bicara tentang modul @Module di Nest. Injeksi ketergantungan dan inversi kontrol memerlukannya sebagai media.
Nestjs mengimplementasikan inversi kontrol dan setuju untuk mengonfigurasi impor, ekspor, dan penyedia modul (@module) untuk mengelola penyedia, yang merupakan injeksi ketergantungan kelas.
Penyedia dapat dipahami sebagai mendaftarkan dan membuat instance kelas-kelas dalam modul saat ini. A dan B berikut dipakai dalam modul saat ini. Jika B mereferensikan A dalam konstruktor, itu mengacu pada instance A dari ModuleD saat ini.
impor { Modul } dari '@nestjs/common'; impor { ModuleX } dari './moduleX'; impor { A } dari './A'; impor { B } dari './B'; @Modul({ impor: [ModuleX], penyedia: [A,B], ekspor: [A] }) kelas ekspor ModulD {} // B kelas B{ konstruktor(a:A){ ini.a = a; } }
exports
mengacu pada kelas-kelas yang dipakai dalam providers
dalam modul saat ini sebagai kelas-kelas yang dapat digunakan bersama oleh modul eksternal. Misalnya, ketika kelas C dari ModuleF dipakai, saya ingin langsung menyuntikkan instance kelas A dari ModuleD. Cukup atur ekspor A di ModuleD, dan impor ModuleD melalui imports
di ModuleF.
Menurut metode penulisan berikut, program kontrol inversi akan secara otomatis memindai dependensi. Pertama, periksa apakah ada penyedia A di penyedia modul Anda sendiri ditemukan, dapatkan A dari ModuleD. Instance dimasukkan ke dalam instance C.
impor { Modul } dari '@nestjs/common'; impor { ModuleD} dari './moduleD'; impor { C } dari './C'; @Modul({ impor: [ModulD], penyedia: [C], }) kelas ekspor ModuleF {} // C kelas C { konstruktor(a:A){ ini.a = a; } }
Oleh karena itu, jika Anda ingin modul eksternal menggunakan instance kelas dari modul saat ini, Anda harus terlebih dahulu menentukan kelas instantiasi di providers
modul saat ini, lalu menentukan dan mengekspor kelas ini, jika tidak, kesalahan akan dilaporkan.
//Benar @Modul({ penyedia: [A], ekspor: [A] }) //Kesalahan @Modul({ penyedia: [], ekspor: [A] })
Melihat kembali proses pencarian instance modulpelengkap selanjutnya
, memang agak kurang jelas. Intinya adalah bahwa kelas-kelas dalam penyedia akan dipakai, dan setelah instantiasi mereka menjadi penyedia. Hanya kelas-kelas dalam penyedia dalam modul yang akan dipakai, dan ekspor dan impor hanyalah konfigurasi hubungan organisasi. Modul akan memprioritaskan penggunaan penyedianya sendiri. Jika tidak, periksa apakah modul yang diimpor memiliki penyedia yang sesuai.
Izinkan saya menyebutkan beberapa poin pengetahuan
ekspor C {.
konstruktor(pribadi a: A) { } }
Karena TypeScript mendukung parameter konstruktor (pribadi, dilindungi, publik, hanya baca) untuk didefinisikan secara implisit dan otomatis sebagai atribut kelas (Properti Parameter), maka tidak perlu menggunakan this.a = a
. Ini adalah cara yang tertulis di Nest.
Konsep metaprogramming tercermin dalam kerangka Nest. Inversi kontrol dan dekorator adalah implementasi metaprogramming. Secara kasar dapat dipahami bahwa inti dari metaprogramming tetaplah pemrograman, namun terdapat beberapa program abstrak di tengahnya. Program abstrak ini dapat mengidentifikasi metadata (seperti data objek di @Module), yang sebenarnya merupakan kemampuan perluasan yang dapat digunakan lainnya program sebagai data. Ketika kita menulis program abstrak seperti itu, kita sedang melakukan metaprogramming.
4.1
Metadata Metadata sering disebutkan dalam dokumen Nest. Konsep metadata bisa membingungkan saat Anda melihatnya untuk pertama kali terjerat.
Pengertian metadata adalah: data yang mendeskripsikan data, terutama informasi yang mendeskripsikan atribut data, dan dapat juga dipahami sebagai data yang mendeskripsikan program.
exports、providers、imports、controllers
yang dikonfigurasi oleh @Module di Nest semuanya merupakan metadata , karena ini adalah data yang digunakan untuk menjelaskan hubungan program. Informasi data ini bukanlah data aktual yang ditampilkan kepada pengguna akhir, tetapi dibaca dan dikenali oleh kerangka program.
4.2 Dekorator Nest
Jika Anda melihat kode sumber dekorator di Nest, Anda akan menemukan bahwa hampir setiap dekorator itu sendiri hanya mendefinisikan metadata melalui metadata refleksi.
@Fungsi ekspordekorator yang dapat disuntikkan
Dapat disuntikkan(pilihan?: Opsi yang Dapat Disuntik): ClassDecorator { kembali (target: objek) => { Reflect.defineMetadata(INJECTABLE_WATERMARK, benar, target); Reflect.defineMetadata(SCOPE_OPTIONS_METADATA, opsi, target); }; }
Ada konsep refleksi di sini, dan refleksi relatif mudah dipahami. Ambil dekorator @Module sebagai contoh untuk mendefinisikan providers
metadata. Ini hanya meneruskan kelas ke dalam array providers
. Ketika program benar-benar berjalan, kelas di providers
akan meneruskannya secara otomatis digunakan oleh program kerangka kerja. Instansiasi menjadi penyedia, dan pengembang tidak perlu secara eksplisit melakukan instantiasi dan injeksi ketergantungan. Sebuah kelas hanya menjadi penyedia setelah dipakai dalam sebuah modul. Kelas-kelas di providers
direfleksikan dan menjadi penyedia. Inversi kontrol adalah teknologi refleksi yang digunakan.
Contoh lainnya adalah ORM (Object Relational Mapping) pada database. Untuk menggunakan ORM, Anda hanya perlu mendefinisikan field tabel, dan perpustakaan ORM akan secara otomatis mengubah data objek menjadi pernyataan SQL.
const data = TableModel.build(); data.waktu = 1; data.browser = 'chrome'; data.simpan(); // SQL: INSERT INTO tableName (time,browser) [{"time":1,"browser":"chrome"}]
Library ORM menggunakan teknologi refleksi, sehingga pengguna hanya perlu memperhatikan data lapangan itu sendiri, dan objeknya adalah refleksi Perpustakaan ORM menjadi pernyataan eksekusi SQL. Pengembang hanya perlu fokus pada bidang data dan tidak perlu menulis SQL.
4.3 mencerminkan-metadata
mencerminkan-metadata adalah perpustakaan refleksi yang digunakan Nest untuk mengelola metadata. mencerminkan-metadata menggunakan WeakMap untuk membuat instance tunggal global, dan menetapkan serta memperoleh metadata dari objek yang didekorasi (kelas, metode, dll.) melalui metode set dan get.
// Lihat saja var _WeakMap = !usePolyfill && typeof WeakMap === "function" ? var Metadata = baru _WeakMap(); fungsi mendefinisikanMetadata(){ MetadataDefineOwn Biasa(){ DapatkanOrCreateMetadataMap(){ var targetMetadata = Metadata.get(O); if (Tidak Terdefinisi(targetMetadata)) { jika (!Buat) kembali tidak terdefinisi; targetMetadata = baru _Peta(); Metadata.set(O, targetMetadata); } var metadataMap = targetMetadata.get(P); if (Tidak Terdefinisi(petadataMap)) { jika (!Buat) kembali tidak terdefinisi; metadataMap = _Peta baru(); targetMetadata.set(P, metadataMap); } kembalikan metadataMap; } } }
mencerminkan-metadata menyimpan metadata orang yang diberi tanda dalam objek tunggal global untuk pengelolaan terpadu. mencerminkan-metadata tidak mengimplementasikan refleksi spesifik, tetapi menyediakan perpustakaan alat untuk membantu implementasi refleksi.
, mari kita lihat pertanyaan sebelumnya.
Mengapa inversi kendali diperlukan?
Apa itu injeksi ketergantungan?
Apa yang dilakukan dekorator?
Apa prinsip implementasi penyedia, impor, dan ekspor dalam modul (@Module)?
1 dan 2 Saya rasa saya sudah menjelaskannya sebelumnya. Jika masih agak kabur, saya sarankan Anda kembali dan membacanya lagi dan membaca beberapa artikel lain untuk membantu Anda memahami pengetahuan melalui pemikiran penulis yang berbeda.
5.1 Masalah [3 4] Ikhtisar:
Nest menggunakan teknologi refleksi untuk mengimplementasikan inversi kontrol dan menyediakan kemampuan metaprogramming. Pengembang menggunakan dekorator @Module untuk mendekorasi kelas dan menentukan metadata (penyediaimportsekspor), dan metadata disimpan secara global. objek (menggunakan perpustakaan refleksi-metadata). Setelah program berjalan, program kontrol di dalam kerangka Nest membaca dan mendaftarkan pohon modul, memindai metadata dan membuat instance kelas untuk menjadi penyedia, dan menyediakannya di semua modul sesuai dengan definisi penyediaimportsekspor dalam metadata modul . Cari instance (penyedia) kelas dependen lain dari kelas saat ini, dan masukkan melalui konstruktor setelah menemukannya.
Artikel ini memiliki banyak konsep dan tidak memberikan analisis yang terlalu detail. Konsep tersebut membutuhkan waktu untuk dipahami secara perlahan. Oke, itu saja. Artikel ini masih membutuhkan banyak usaha. Teman-teman yang menyukainya semoga bisa terhubung tiga kali dengan satu klik~