Rumah > hujung hadapan web > tutorial js > Menguasai Prinsip Penyongsangan Ketergantungan: Amalan Terbaik untuk Kod Bersih dengan DI

Menguasai Prinsip Penyongsangan Ketergantungan: Amalan Terbaik untuk Kod Bersih dengan DI

Linda Hamilton
Lepaskan: 2024-11-30 00:25:11
asal
280 orang telah melayarinya

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();
 }
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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:

Mastering the Dependency Inversion Principle: Best Practices for Clean Code with 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()));
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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.

Mastering the Dependency Inversion Principle: Best Practices for Clean Code with DI

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.

Mastering the Dependency Inversion Principle: Best Practices for Clean Code with DI

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();
 }
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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.

Mastering the Dependency Inversion Principle: Best Practices for Clean Code with DI

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();
 }
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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()));
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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();
Salin selepas log masuk
Salin selepas log masuk
  1. 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.

  2. 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.

  3. 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.

Mastering the Dependency Inversion Principle: Best Practices for Clean Code with DI

npm i friendly-di reflect-metadata
Salin selepas log masuk

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();
 }
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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()));
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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();
Salin selepas log masuk
Salin selepas log masuk

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!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan