पिछले भाग:
एक वर्ग के पास परिवर्तन का केवल एक ही कारण होना चाहिए
// 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()) { // ... } } }
सॉफ़्टवेयर इकाइयाँ (कक्षाएँ, मॉड्यूल, फ़ंक्शंस) विस्तार के लिए खुली होनी चाहिए लेकिन संशोधन के लिए बंद होनी चाहिए
// 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(...); } }
सुपरक्लास की वस्तुओं को एप्लिकेशन को तोड़े बिना उसके उपवर्गों की वस्तुओं से बदला जाना चाहिए।
// 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
कार्यक्षमता नहीं टूटेगी।