اصل Liskov Substitution Principle در SOLID چیست؟



visibility  
mode_comment   ۲

شاید برایتان اتفاق افتاده باشد که شرکتی از شما خواسته کدهای برنامه نویس دیگری را تکمیل کنید. اگر شرکت در قبال تمیزی و طراحی کدهای توسعه دهندگان سابق خود حساسیت نداشته باشد، احتمالا از آن تجربه به عنوان یکی از خاطرات تلخ خود یاد خواهید کرد! کدهای کثیف، پر از بوی بد (Bad Smell) در همه جای خود است! البته اینجا شما با یک غذای گندیده مواجه نیستید!

SOLID چیست

بوی بد در برنامه نویسی اصطلاحا به اشتباهاتی گفته می شود که بعدها باعث بروز مشکلات بزرگتر در کد می شوند. وقتی از عبارت طراحی کد خوب استفاده می کنیم، منظورمان کدی است که بوی بد نداشته باشد (یا حداقل به میزان قابل تحملی بوی بد داشته باشد)!

برای دستیابی به یک کد خوشبو باید اصول طراحی کد خوب را رعایت کنیم. یکی از  مجموعه اصولی که برای طراحی کد خوب باید آن ها را مد نظر قرار دهیم به اصول SOLID معروف اند. اصول SOLID (بخوانید سالید) عبارت اند از:

  1. Single Responsibility Principle یا اصل تک وظیفگی (SRP)
  2. Open/Closed Principle یا اصل باز و بسته بودن (OCP)
  3. Liskov Substitution Principle یا اصل جانشینی لیسکف (LSP)
  4. Interface Segregation Principle یا اصل تفکیک Interface (ISP)
  5. Dependency Inversion Principle یا اصل وارونه کردن وابستگی (DIP)

در این مطلب به معرفی اصل سوم یعنی اصل جانشینی لیسکف (Liskov Substitution Principle) می پردازیم. اصل جانشینی به یکی از مشکل ترین اصول SOLID معروف است اما به هر حال ما در این مقاله آن را به ساده ترین شکل ممکن به شما یاد می دهیم. پس نگران نباشید و تا آخر مقاله به دقت همراهمان باشید!

اصل جانشینی لیسکف چیست

اصل جانشینی لیسکف اولین بار در سال 1987 توسط خانم باربارا لیسکف در کنفرانسش با عنوان "انتزاع (Abstraction) داده" معرفی شد. او بعدها در مقاله ای که به همراه خانم ژانت وینگ منتشر کرد، اصل جانشینی را اینطور تعریف کرد:

"فرض کنید Φ(x) یک خاصیت آبجکت x  از نوع کلاس T باشد. در این صورت با فرض اینکه S یک زیر مجموعه از نوع T باشد، Φ(y) باید برای آبجکت یا آبجکت های y از نوع کلاس S به درستی عمل کند."

اگر کمی صادقانه صحبت کنیم، تعریف بالا بیشتر شبیه یک جور قاعده آزاردهنده جبری سخت است! اما به زبان ساده می توانیم آن را اینگونه بیان کنیم:

info نکته :

اصل جانشینی لیسکف می گوید: آبجکت های کلاس های والد و فرزند، باید بتوانند بدون به وجود آمدن هیچ مشکلی در کدها به جای هم استفاده شوند.

نقض کردن این قانون درست مثل این است که بخوایم گربه ای را به جای شیر جا بزنیم! گربه نمی تواند غرش کند و شیر نمی تواند میو میو کند. بنابراین وراثت کلاس گربه از شیر احتمالا خیلی به آرمان های اصل جانشینی نزدیک نیست!

SOLID چیست

چرا باید از اصل جانشینی استفاده کنیم

در ابتدای یادگیری برنامه نویسی شی گرا احتمالا همیشه به شما گفته شده هر زمان که رابطه بین دو موجودیت از نوع is-A باشد، نشانه آن است که باید از وراثت یا Inheritance استفاده کنید. اما واقعیت این است که این موضوع در همه مسائل درست از آب در نمی آید و استفاده همیشگی آن در بعضی موارد مشکلاتی به همراه دارد. اصل جانشینی برای این استفاده می شود که مطمئن شویم وراثت همیشه به درستی به کار رفته است.

more  بیشتر بخوانید : اصل Single Responsibility در SOLID چیست؟

برای درک بهتر موضوع اجازه بدهید یک مثال ساده بزنیم. فرض کنید در برنامه یک کلاس مستطیل و یک کلاس مربع داریم. به نظر شما رابطه بین این دو کلاس باید چگونه باشد؟ همانطور که می دانید مربع یک نوع مستطیل است. بنابراین با یک رابطه از نوع is-A مواجهیم. اما احتمالا چون به تازگی در یک مقاله بدبینانه مثل این یکی، خوانده اید که استفاده همیشگی از وراثت در این موارد بوی بد تولید می کند، از این که جواب بدهید وراثت می ترسید!

اما فرض کنید یک برنامه نویس بی دقت برای حل این مسئله به سرعت از وراثت استفاده کرده باشد. می خواهیم متدی داشته باشیم که مساحت شکل را با استفاده از اتریبیوت طول و عرض آبجکت شکل محاسبه کند. اما مشکل اینجاست که مربع بر خلاف مستطیل برای محاسبه مساحت تنها به عرض احتیاج دارد. حال یا باید به کلاس مستطیل دست بریم و آن را برای قبول عذر مربع ها سازگار کنیم و یا برنامه بخاطر بی مقدار ماندن اتریبیوت عرض در متد محاسبه مساحت با Exception مواجه شود. با اعمال روش اول اصل Open/Closed در SOLID را نقض کرده ایم و با اعمال روش دوم برنامه دارای اشکال است.

SOLID چیست

اصل لیسکْف در دنیای واقعی

فرض کنید در برنامه کلاسی داریم که وظیفه آن پیدا کردن ایمیل اولیه (Primary) از یک شی ایمیل است. وظیفه پیدا کردن ایمیل پرایمری در متد extract() تعریف شده است. حال می خواهیم کلاسی داشته باشیم که وظیفه آن پیدا کردن ایمیل ثانویه (Secondary) باشد. برای رعایت اصل جانشینی لیسکوف کافی است به این صورت عمل کنیم:

کلاس پایه یا والد همان کلاس PrimaryEmailExtractor و کلاس فرزند SecondaryEmailExtractor است. برای بازنویسی عملکرد متد extract() این متد را در کلاس فرزند override کرده ایم. با این کار نه تنها اصل Open/Closed را رعایت کرده ایم و در کدهای کلاس والد دست نبرده ایم، بلکه طبق اصل جانشینی لیسکف می توانیم متد extract() از شی کلاس Secondary را به جای متد extract() از شی کلاس Primary و بالعکس استفاده کنیم.

نتیجه گیری

در این نوشته با اصل سوم از اصول SOLID در طراحی کد آشنا شدید. اصول SOLID مجموعه ای از پنج اصل پایه ای در شیوه های درست برنامه نویسی است. اصول SOLID به شما کمک می کنند از بو های بد کد یا Code Smells اجنتاب کنید! با رعایت این اصول می توانید کدهایی تمیز (Clean Code) بنویسید. تغییر در کدها و گسترش آن ها با رعایت SOLID ساده، و هزینه های مالی و زمانی آن کاهش می یابد. پس می بینید که یادگیری تک تک این اصول برای یک برنامه نویس تا چه حد حیاتی است. بنابراین بهتر است حتما خواندن این نوع مقالات را جدی بگیرید! آیا شما تجربه ای از بوی بد ناشی از رعایت نکردن اصل جانشینی لیسکف داشته اید؟! از خواندن نظرات شما خوشحال می شویم!

7Learn Experts
comment دیدگاه کاربران
مجید زادگی replyپاسخ

سلام و عرض ادب
ممنون از مقالات خوبی که منتشر می کنید.
معمولا بیان و درک این اصول بسیار ساده به نظر می رسه اما خیلی کم میشه که این اصول رو رعایت کنیم، من این 5 اصل رو پرینت گرفتم و جلوی میز کارم گذاشتم تا همیشه حواسم باشه دارم چکار می کنم!
بسیار عالی
متشکرم

زهرا فرحمند

سلام جناب زادگی خیلی خوشحالم که استفاده کردید. درسته واقعا رعایت این اصول می تونه از به هم ریختگی ها و مشکلات Scaling بعدی جلوگیری کنه. موفق باشید 🙂

add_circle ارسال دیدگاه

خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :