


Menguasai Prinsip Penyongsangan Ketergantungan: Amalan Terbaik untuk Kod Bersih dengan DI
Jika anda biasa dengan pengaturcaraan berorientasikan objek, atau baru mula menerokainya, anda mungkin pernah menemui akronim PEJAL. SOLID mewakili satu set prinsip yang direka untuk membantu pembangun menulis kod yang bersih, boleh diselenggara dan berskala. Dalam artikel ini, kami akan menumpukan pada "D" dalam SOLID, yang bermaksud Prinsip Penyongsangan Kebergantungan.
Tetapi sebelum menyelami butirannya, mari kita luangkan sedikit masa untuk memahami "mengapa" di sebalik prinsip ini.
Dalam pengaturcaraan berorientasikan objek, kami biasanya memecahkan aplikasi kami ke dalam kelas, masing-masing merangkumi logik perniagaan tertentu dan berinteraksi dengan kelas lain. Sebagai contoh, bayangkan kedai dalam talian yang mudah di mana pengguna boleh menambah produk pada troli beli-belah mereka. Senario ini boleh dimodelkan dengan beberapa kelas yang bekerjasama untuk mengurus operasi kedai. Mari kita pertimbangkan contoh ini sebagai asas untuk meneroka bagaimana Prinsip Penyongsangan Kebergantungan boleh menambah baik reka bentuk sistem kami.
class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor() { this.productService = new ProductService(); } getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor() { this.orderService = new OrderService(); } getUserOrders() { return this.orderService.getOrdersForUser(); } }
Seperti yang dapat kita lihat, kebergantungan seperti OrderService dan ProductService digandingkan rapat dalam pembina kelas. Kebergantungan langsung ini menyukarkan untuk menggantikan atau mengejek komponen ini, yang menimbulkan cabaran dalam hal menguji atau menukar pelaksanaan.
Suntikan Ketergantungan (DI)
Corak Dependency Injection (DI) menawarkan penyelesaian kepada masalah ini. Dengan mengikut corak DI, kami boleh memisahkan kebergantungan ini dan menjadikan kod kami lebih fleksibel dan boleh diuji. Begini cara kita boleh memfaktorkan semula kod untuk melaksanakan DI:
class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor(private productService: ProductService) {} getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor(private orderService: OrderService) {} getUserOrders() { return this.orderService.getOrdersForUser(); } } new UserService(new OrderService(new ProductService()));
Kami secara eksplisit menyampaikan kebergantungan kepada pembina setiap perkhidmatan, yang, walaupun satu langkah ke arah yang betul, masih menghasilkan kelas yang digabungkan dengan ketat. Pendekatan ini meningkatkan sedikit fleksibiliti, tetapi ia tidak menangani sepenuhnya isu asas untuk menjadikan kod kami lebih modular dan mudah diuji.
Prinsip Penyongsangan Ketergantungan (DiP)
Prinsip Penyongsangan Ketergantungan (DiP) mengambil langkah ini lebih jauh dengan menjawab soalan penting: Apakah yang harus kita lalui? Prinsip ini mencadangkan bahawa daripada melepasi pelaksanaan konkrit, kita harus lulus hanya abstraksi yang diperlukan—khususnya, kebergantungan yang sepadan dengan antara muka yang dijangkakan.
Sebagai contoh, pertimbangkan kelas ProductService dengan kaedah getProducts yang mengembalikan tatasusunan produk. Daripada menggandingkan terus ProductService kepada pelaksanaan tertentu (mis., mengambil data daripada pangkalan data), kami boleh melaksanakannya dalam pelbagai cara. Satu pelaksanaan mungkin mengambil produk daripada pangkalan data, manakala satu lagi mungkin mengembalikan objek JSON berkod keras untuk ujian. Perkara utama ialah kedua-dua pelaksanaan berkongsi antara muka yang sama, memastikan fleksibiliti dan kebolehtukaran.
Penyongsangan Kawalan (IoC) dan Pencari Perkhidmatan
Untuk mempraktikkan prinsip ini, kami sering bergantung pada corak yang dipanggil Penyongsangan Kawalan (IoC). IoC ialah teknik di mana kawalan ke atas penciptaan dan pengurusan kebergantungan dipindahkan daripada kelas itu sendiri kepada komponen luaran. Ini biasanya dilaksanakan melalui bekas Suntikan Ketergantungan atau Pencari Perkhidmatan, yang bertindak sebagai pendaftaran yang daripadanya kami boleh meminta kebergantungan yang diperlukan. Dengan IoC, kami boleh menyuntik kebergantungan yang sesuai secara dinamik tanpa pengekodan keras ke dalam pembina kelas, menjadikan sistem lebih modular dan lebih mudah diselenggara.
class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor() { this.productService = new ProductService(); } getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor() { this.orderService = new OrderService(); } getUserOrders() { return this.orderService.getOrdersForUser(); } }
Seperti yang kita lihat, kebergantungan didaftarkan dalam bekas, yang membolehkannya diganti atau ditukar apabila perlu. Fleksibiliti ini merupakan kelebihan utama, kerana ia menggalakkan gandingan longgar antara komponen.
Walau bagaimanapun, pendekatan ini mempunyai beberapa kelemahan. Memandangkan kebergantungan diselesaikan pada masa jalan, ia boleh membawa kepada ralat masa jalan jika berlaku masalah (cth., jika kebergantungan tiada atau tidak serasi). Tambahan pula, tiada jaminan bahawa kebergantungan yang didaftarkan akan mematuhi antara muka yang dijangkakan, yang boleh menyebabkan isu halus. Kaedah penyelesaian pergantungan ini sering dirujuk sebagai corak Pencari Perkhidmatan dan ia dianggap sebagai anti-corak dalam banyak kes kerana pergantungannya pada resolusi masa jalan dan potensinya untuk mengaburkan kebergantungan.
InversifyJS
Salah satu perpustakaan paling popular dalam JavaScript untuk melaksanakan corak Penyongsangan Kawalan (IoC) ialah InversifyJS. Ia menyediakan rangka kerja yang teguh dan fleksibel untuk mengurus kebergantungan dengan cara yang bersih dan modular. Walau bagaimanapun, InversifyJS mempunyai beberapa kelemahan. Satu had utama ialah jumlah kod boilerplate yang diperlukan untuk menyediakan dan mengurus kebergantungan. Selain itu, ia sering memerlukan penstrukturan aplikasi anda dengan cara tertentu, yang mungkin tidak sesuai dengan setiap projek.
Alternatif kepada InversifyJS ialah Friendly-DI, pendekatan yang ringan dan lebih diperkemas untuk mengurus kebergantungan dalam aplikasi JavaScript dan TypeScript. Ia diilhamkan oleh sistem DI dalam rangka kerja seperti Angular dan NestJS tetapi direka bentuk untuk menjadi lebih minimum dan kurang bertele-tele.
Beberapa kelebihan utama Friendly-DI termasuk:
- Saiz kecil: Hanya 2 KB tanpa kebergantungan luaran.
- Merentas platform: Berfungsi dengan lancar dalam kedua-dua penyemak imbas dan persekitaran Node.js.
- API Mudah: Intuitif dan mudah digunakan, dengan konfigurasi minimum.
- Lesen MIT: Sumber terbuka dengan pelesenan permisif.
Walau bagaimanapun, adalah penting untuk ambil perhatian bahawa Friendly-DI direka khusus untuk TypeScript dan anda perlu memasang kebergantungannya sebelum anda boleh mula menggunakannya.
class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor() { this.productService = new ProductService(); } getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor() { this.orderService = new OrderService(); } getUserOrders() { return this.orderService.getOrdersForUser(); } }
Dan juga lanjutkan tsconfig.json:
class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor(private productService: ProductService) {} getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor(private orderService: OrderService) {} getUserOrders() { return this.orderService.getOrdersForUser(); } } new UserService(new OrderService(new ProductService()));
Contoh di atas boleh diubah suai dengan Friendly-DI:
class ServiceLocator { static #modules = new Map(); static get(moduleName: string) { return ServiceLocator.#modules.get(moduleName); } static set(moduleName: string, exp: never) { ServiceLocator.#modules.set(moduleName, exp); } } class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor() { const ProductService = ServiceLocator.get('ProductService'); this.productService = new ProductService(); } getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor() { const OrderService = ServiceLocator.get('OrderService'); this.orderService = new OrderService(); } getUserOrders() { return this.orderService.getOrdersForUser(); } } ServiceLocator.set('ProductService', ProductService); ServiceLocator.set('OrderService', OrderService); new UserService();
Seperti yang dapat kita lihat, kami telah menambah penghias @Injectable(), yang menandakan kelas kami sebagai boleh disuntik, menandakan bahawa mereka adalah sebahagian daripada sistem suntikan pergantungan. Penghias ini membolehkan bekas DI mengetahui bahawa kelas ini boleh dibuat seketika dan disuntik di mana diperlukan.
Apabila mengisytiharkan kelas sebagai kebergantungan dalam pembina, kami tidak mengikat secara langsung kepada kelas konkrit itu sendiri. Sebaliknya, kami mentakrifkan pergantungan dari segi antara mukanya. Ini mengasingkan kod kami daripada pelaksanaan khusus dan membolehkan fleksibiliti yang lebih besar, menjadikannya lebih mudah untuk menukar atau mengejek kebergantungan apabila diperlukan.
Dalam contoh ini, kami meletakkan UserService kami dalam kelas App. Corak ini dikenali sebagai Akar Komposisi. Akar Komposisi ialah tempat utama dalam aplikasi di mana semua kebergantungan dipasang dan disuntik — pada asasnya "akar" graf kebergantungan aplikasi kami. Dengan mengekalkan logik ini di satu tempat, kami mengekalkan kawalan yang lebih baik terhadap cara kebergantungan diselesaikan dan disuntik ke seluruh apl.
Langkah terakhir ialah mendaftar kelas Apl dalam Kontena DI, yang akan membolehkan kontena mengurus kitaran hayat dan suntikan semua kebergantungan apabila aplikasi bermula.
npm i friendly-di reflect-metadata
Jika kami perlu menggantikan mana-mana kelas dalam aplikasi kami, kami hanya perlu mencipta kelas olok-olok mengikut antara muka asal:
class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor() { this.productService = new ProductService(); } getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor() { this.orderService = new OrderService(); } getUserOrders() { return this.orderService.getOrdersForUser(); } }
dan kemudian gunakan kaedah ganti di mana kami mengisytiharkan kelas yang boleh diganti untuk mengejek kelas:
class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor(private productService: ProductService) {} getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor(private orderService: OrderService) {} getUserOrders() { return this.orderService.getOrdersForUser(); } } new UserService(new OrderService(new ProductService()));
Friendly-DI kita boleh buat ganti berkali-kali:
class ServiceLocator { static #modules = new Map(); static get(moduleName: string) { return ServiceLocator.#modules.get(moduleName); } static set(moduleName: string, exp: never) { ServiceLocator.#modules.set(moduleName, exp); } } class ProductService { getProducts() { return ['product 1', 'product 2', 'product 3']; } } class OrderService { constructor() { const ProductService = ServiceLocator.get('ProductService'); this.productService = new ProductService(); } getOrdersForUser() { return this.productService.getProducts(); } } class UserService { constructor() { const OrderService = ServiceLocator.get('OrderService'); this.orderService = new OrderService(); } getUserOrders() { return this.orderService.getOrdersForUser(); } } ServiceLocator.set('ProductService', ProductService); ServiceLocator.set('OrderService', OrderService); new UserService();
Itu sahaja, jika anda mempunyai sebarang komen atau penjelasan mengenai topik ini, sila tulis pendapat anda dalam ulasan.
Atas ialah kandungan terperinci Menguasai Prinsip Penyongsangan Ketergantungan: Amalan Terbaik untuk Kod Bersih dengan DI. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas











Python lebih sesuai untuk pemula, dengan lengkung pembelajaran yang lancar dan sintaks ringkas; JavaScript sesuai untuk pembangunan front-end, dengan lengkung pembelajaran yang curam dan sintaks yang fleksibel. 1. Sintaks Python adalah intuitif dan sesuai untuk sains data dan pembangunan back-end. 2. JavaScript adalah fleksibel dan digunakan secara meluas dalam pengaturcaraan depan dan pelayan.

Peralihan dari C/C ke JavaScript memerlukan menyesuaikan diri dengan menaip dinamik, pengumpulan sampah dan pengaturcaraan asynchronous. 1) C/C adalah bahasa yang ditaip secara statik yang memerlukan pengurusan memori manual, manakala JavaScript ditaip secara dinamik dan pengumpulan sampah diproses secara automatik. 2) C/C perlu dikumpulkan ke dalam kod mesin, manakala JavaScript adalah bahasa yang ditafsirkan. 3) JavaScript memperkenalkan konsep seperti penutupan, rantaian prototaip dan janji, yang meningkatkan keupayaan pengaturcaraan fleksibiliti dan asynchronous.

Penggunaan utama JavaScript dalam pembangunan web termasuk interaksi klien, pengesahan bentuk dan komunikasi tak segerak. 1) kemas kini kandungan dinamik dan interaksi pengguna melalui operasi DOM; 2) pengesahan pelanggan dijalankan sebelum pengguna mengemukakan data untuk meningkatkan pengalaman pengguna; 3) Komunikasi yang tidak bersesuaian dengan pelayan dicapai melalui teknologi Ajax.

Aplikasi JavaScript di dunia nyata termasuk pembangunan depan dan back-end. 1) Memaparkan aplikasi front-end dengan membina aplikasi senarai TODO, yang melibatkan operasi DOM dan pemprosesan acara. 2) Membina Restfulapi melalui Node.js dan menyatakan untuk menunjukkan aplikasi back-end.

Memahami bagaimana enjin JavaScript berfungsi secara dalaman adalah penting kepada pemaju kerana ia membantu menulis kod yang lebih cekap dan memahami kesesakan prestasi dan strategi pengoptimuman. 1) aliran kerja enjin termasuk tiga peringkat: parsing, penyusun dan pelaksanaan; 2) Semasa proses pelaksanaan, enjin akan melakukan pengoptimuman dinamik, seperti cache dalam talian dan kelas tersembunyi; 3) Amalan terbaik termasuk mengelakkan pembolehubah global, mengoptimumkan gelung, menggunakan const dan membiarkan, dan mengelakkan penggunaan penutupan yang berlebihan.

Python dan JavaScript mempunyai kelebihan dan kekurangan mereka sendiri dari segi komuniti, perpustakaan dan sumber. 1) Komuniti Python mesra dan sesuai untuk pemula, tetapi sumber pembangunan depan tidak kaya dengan JavaScript. 2) Python berkuasa dalam bidang sains data dan perpustakaan pembelajaran mesin, sementara JavaScript lebih baik dalam perpustakaan pembangunan dan kerangka pembangunan depan. 3) Kedua -duanya mempunyai sumber pembelajaran yang kaya, tetapi Python sesuai untuk memulakan dengan dokumen rasmi, sementara JavaScript lebih baik dengan MDNWebDocs. Pilihan harus berdasarkan keperluan projek dan kepentingan peribadi.

Kedua -dua pilihan Python dan JavaScript dalam persekitaran pembangunan adalah penting. 1) Persekitaran pembangunan Python termasuk Pycharm, Jupyternotebook dan Anaconda, yang sesuai untuk sains data dan prototaip cepat. 2) Persekitaran pembangunan JavaScript termasuk node.js, vscode dan webpack, yang sesuai untuk pembangunan front-end dan back-end. Memilih alat yang betul mengikut keperluan projek dapat meningkatkan kecekapan pembangunan dan kadar kejayaan projek.

C dan C memainkan peranan penting dalam enjin JavaScript, terutamanya digunakan untuk melaksanakan jurubahasa dan penyusun JIT. 1) C digunakan untuk menghuraikan kod sumber JavaScript dan menghasilkan pokok sintaks abstrak. 2) C bertanggungjawab untuk menjana dan melaksanakan bytecode. 3) C melaksanakan pengkompil JIT, mengoptimumkan dan menyusun kod hot-spot semasa runtime, dan dengan ketara meningkatkan kecekapan pelaksanaan JavaScript.
