paint-brush
स्वच्छ कोड: टीएस में एकल जिम्मेदारी, खुला/बंद, लिस्कोव प्रतिस्थापन ठोस सिद्धांत [भाग 4]द्वारा@alenaananich
4,731 रीडिंग
4,731 रीडिंग

स्वच्छ कोड: टीएस में एकल जिम्मेदारी, खुला/बंद, लिस्कोव प्रतिस्थापन ठोस सिद्धांत [भाग 4]

द्वारा Alena Ananich7m2023/11/09
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

इस लेख में, हम व्यावहारिक उदाहरणों पर तीन पहले ठोस सिद्धांतों पर एक नज़र डालेंगे: एकल जिम्मेदारी सिद्धांत, खुला/बंद सिद्धांत और लिस्कोव प्रतिस्थापन सिद्धांत।
featured image - स्वच्छ कोड: टीएस में एकल जिम्मेदारी, खुला/बंद, लिस्कोव प्रतिस्थापन ठोस सिद्धांत [भाग 4]
Alena Ananich HackerNoon profile picture


पिछले भाग:


हम अपने कोड को स्वच्छ, लचीला और रखरखाव योग्य बनाने के तरीकों पर विचार करना जारी रख रहे हैं। और अब, आइए स्वच्छ वास्तुशिल्प समाधानों की जांच शुरू करें।


SOLID सिद्धांत रॉबर्ट सी. मार्टिन द्वारा पेश किए गए थे और इन्हें व्यापक रूप से ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग और सॉफ़्टवेयर डिज़ाइन में सर्वोत्तम प्रथाओं के रूप में माना जाता है।


इस लेख में, हम व्यावहारिक उदाहरणों पर तीन पहले ठोस सिद्धांतों पर एक नज़र डालेंगे: एकल जिम्मेदारी सिद्धांत, खुला/बंद सिद्धांत, और लिस्कोव प्रतिस्थापन सिद्धांत।

विषयसूची:

  1. एकल उत्तरदायित्व सिद्धांत
  2. खुला/बंद सिद्धांत
  3. लिस्कोव प्रतिस्थापन सिद्धांत

1. एकल उत्तरदायित्व सिद्धांत (एसआरपी)

एक वर्ग के पास परिवर्तन का केवल एक ही कारण होना चाहिए


दूसरे शब्दों में, एक वर्ग के पास एक ही जिम्मेदारी या कार्य होना चाहिए। यह महत्वपूर्ण है क्योंकि एकल जिम्मेदारी वाले वर्ग को समझना, संशोधित करना और बनाए रखना आसान होता है। कोड के एक क्षेत्र में परिवर्तन से पूरे सिस्टम पर असर नहीं पड़ेगा, जिससे बग आने का जोखिम कम हो जाएगा।


आइए एक व्यावहारिक उदाहरण और एकल जिम्मेदारी सिद्धांत का पालन करने के तरीकों पर एक नज़र डालें:

 // Bad class UserSettingsService { constructor(user: IUser) { this.user = user; } changeSettings(settings: IUserSettings): void { if (this.isUserValidated()) { // ... } } getUserInfo(): Promise<IUserSettings> { // ... } async isUserValidated(): Promise<boolean> { const userInfo = await this.getUserInfo(); // ... } }

इस उदाहरण में, हमारा वर्ग विभिन्न दिशाओं में कार्य करता है: यह संदर्भ स्थापित करता है, इसे बदलता है, और इसे मान्य करता है।


एसआरपी का पालन करने के लिए, हमें इन विभिन्न जिम्मेदारियों को विभाजित करने की आवश्यकता है।

 // Better class UserAuth { constructor(user: IUser) { this.user = user; } getUserInfo(): Promise<IUserSettings> { // ... } async isUserValidated(): boolean { const userInfo = await this.getUserInfo(); // ... } } class UserSettings { constructor(user: IUser) { this.user = user; this.auth = new UserAuth(user); } changeSettings(settings: IUserSettings): void { if (this.auth.isUserValidated()) { // ... } } }


यह महत्वपूर्ण क्यों है?

एसआरपी का लक्ष्य अंतर-निर्भरता से उत्पन्न होने वाली चुनौतियों को कम करते हुए, कोड मॉड्यूलैरिटी को बढ़ाना है। कोड को फ़ंक्शंस, अलग-अलग कक्षाओं में व्यवस्थित करने और मॉड्यूलरिटी को बढ़ावा देने से, यह अधिक पुन: प्रयोज्य हो जाता है, जिससे समय की बचत होती है जो अन्यथा मौजूदा कार्यक्षमता को फिर से कोड करने में खर्च हो सकता है।

2. खुला/बंद सिद्धांत (ओसीपी)

सॉफ़्टवेयर इकाइयाँ (कक्षाएँ, मॉड्यूल, फ़ंक्शंस) विस्तार के लिए खुली होनी चाहिए लेकिन संशोधन के लिए बंद होनी चाहिए


आपको मौजूदा कोड को बदले बिना नई कार्यक्षमता जोड़ने में सक्षम होना चाहिए। यह महत्वपूर्ण है क्योंकि इस सिद्धांत का पालन करके, आप मौजूदा कोड की स्थिरता को जोखिम में डाले बिना अपने सिस्टम में नई सुविधाएँ या घटक पेश कर सकते हैं।


यह कोड पुन: प्रयोज्य को बढ़ावा देता है और कार्यक्षमता का विस्तार करते समय व्यापक परिवर्तनों की आवश्यकता को कम करता है।

 // Bad class Product { id: number; name: string[]; price: number; protected constructor(id: number, name: string[], price: number) { this.id = id; this.name = name; this.price = price; } } class Ananas extends Product { constructor(id: number, name: string[], price: number) { super(id, name, price); } } class Banana extends Product { constructor(id: number, name: string[], price: string) { super(id, name, price); } } class HttpRequestCost { constructor(product: Product) { this.product = product; } getDeliveryCost(): number { if (product instanceOf Ananas) { return requestAnanas(url).then(...); } if (product instanceOf Banana) { return requestBanana(url).then(...); } } } function requestAnanas(url: string): Promise<ICost> { // logic for ananas } function requestBanana(url: string): Promise<ICost> { // logic for bananas }

इस उदाहरण में, समस्या वर्ग HttpRequestCost में है, जिसमें getDeliveryCost विधि में विभिन्न प्रकार के उत्पादों की गणना के लिए शर्तें शामिल हैं, और हम प्रत्येक प्रकार के उत्पाद के लिए अलग-अलग तरीकों का उपयोग करते हैं। इसलिए, यदि हमें एक नए प्रकार का उत्पाद जोड़ने की आवश्यकता है, तो हमें HttpRequestCost वर्ग को संशोधित करना चाहिए, और यह सुरक्षित नहीं है; हमें अप्रत्याशित परिणाम मिल सकते हैं.


इससे बचने के लिए, हमें बिना किसी अहसास के Product वर्ग में एक अमूर्त विधि request बनाना चाहिए। विशेष बोध को ये वर्ग विरासत में मिले होंगे: अनानास और केला। उन्हें अपने लिए अनुरोध का एहसास होगा।


HttpRequestCost Product वर्ग इंटरफ़ेस के बाद product पैरामीटर लेगा, और जब हम HttpRequestCost में विशेष निर्भरता पास करते हैं, तो यह पहले से ही अपने लिए request विधि का एहसास कर लेगा।

 // Better abstract class Product { id: number; name: string[]; price: string; constructor(id: number, name: string[], price: string) { this.id = id; this.name = name; this.price = price; } abstract request(url: string): void; } class Ananas extends Product { constructor(id: number, name: string[], price: string) { super(id, name, price); } request(url: string): void { // logic for ananas } } class Banana extends Product { constructor(id: number, name: string[], price: string) { super(id, name, price); } request(url: string): void { // logic for bananas } } class HttpRequestCost { constructor(product: Product) { this.product = product; } request(): Promise<void> { return this.product.request(url).then(...); } }


यह महत्वपूर्ण क्यों है?

इस सिद्धांत का पालन करके, आप कोड युग्मन को कम करेंगे और सिस्टम को अप्रत्याशित व्यवहार से बचाएंगे।

3. लिस्कोव प्रतिस्थापन सिद्धांत (एलएसपी)

सुपरक्लास की वस्तुओं को एप्लिकेशन को तोड़े बिना उसके उपवर्गों की वस्तुओं से बदला जाना चाहिए।


इस सिद्धांत को समझने के लिए, आइए इस उदाहरण पर एक नज़र डालें:

 // Bad class Worker { work(): void {/../} access(): void { console.log('Have an access to closed perimeter'); } } class Programmer extends Worker { createDatabase(): void {/../} } class Seller extends Worker { sale(): void {/../} } class Designer extends Worker { access(): void { throwError('No access'); } }

इस उदाहरण में, हमारे पास Contractor वर्ग के साथ एक समस्या है। Designer , Programmer और Seller सभी श्रमिक हैं, और उन्हें मूल वर्ग Worker से विरासत में मिला है। लेकिन साथ ही, डिजाइनरों के पास बंद परिधि तक पहुंच नहीं है क्योंकि वे ठेकेदार हैं, कर्मचारी नहीं। और हमने access विधि को ओवरराइड कर दिया है और लिस्कोव प्रतिस्थापन सिद्धांत को तोड़ दिया है।


यह सिद्धांत हमें बताता है कि यदि हम सुपरक्लास Worker उसके उपवर्ग, उदाहरण के लिए Designer वर्ग, से प्रतिस्थापित करते हैं, तो कार्यक्षमता नहीं टूटनी चाहिए। लेकिन अगर हम ऐसा करते हैं, तो Programmer वर्ग की कार्यक्षमता टूट जाएगी - access विधि में Designer वर्ग से अप्रत्याशित प्राप्ति होगी।


लिस्कोव प्रतिस्थापन सिद्धांत का पालन करते हुए, हमें उपवर्गों में अहसासों को दोबारा नहीं लिखना चाहिए बल्कि अमूर्तता की नई परतें बनाने की जरूरत है जहां हम प्रत्येक प्रकार के अमूर्तन के लिए विशेष अहसासों को परिभाषित करते हैं।


आइए इसे ठीक करें:

 // Better class Worker { work(): void {/../} } class Employee extends Worker { access(): void { console.log('Have an access to closed perimeter'); } } class Contractor extends Worker { addNewContract(): void {/../} } class Programmer extends Employee { createDatabase(): void {/../} } class Saler extends Employee { sale(): void {/../} } class Designer extends Contractor { makeDesign(): void {/../} }

हमने अमूर्त Employee और Contractor की नई परतें बनाईं और access पद्धति को Employee वर्ग में स्थानांतरित कर दिया और विशिष्ट अहसास को परिभाषित किया। यदि हम Worker क्लास को सबक्लास Contractor से बदल देते हैं, तो Worker कार्यक्षमता नहीं टूटेगी।

यह महत्वपूर्ण क्यों है?

यदि आप एलएसपी का पालन करते हैं, तो आप किसी भी उपवर्ग उदाहरण को प्रतिस्थापित कर सकते हैं जहां बेस क्लास उदाहरण अपेक्षित है, और प्रोग्राम को अभी भी इच्छित के अनुसार काम करना चाहिए। यह कोड के पुन: उपयोग, मॉड्यूलरिटी को बढ़ावा देता है और आपके कोड को परिवर्तनों के प्रति अधिक लचीला बनाता है।


अगले लेख में, हम इंटरफ़ेस पृथक्करण और निर्भरता व्युत्क्रम SOLID सिद्धांतों पर एक नज़र डालेंगे।