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

دسته بندی: برنامه نویسی
سطح مقاله: پیشرفته
زمان مطالعه: 9 دقیقه
۰۹ اردیبهشت ۱۳۹۸
فارسی
اصل جانشینی لیسکف
English
Liskov Substitution Principle

شاید برایتان اتفاق افتاده باشد که شرکتی از شما خواسته کدهای برنامه نویس دیگری را تکمیل کنید. اگر شرکت در قبال تمیزی و طراحی کدهای توسعه دهندگان سابق خود حساسیت نداشته باشد، احتمالا از آن تجربه به عنوان یکی از خاطرات تلخ خود یاد خواهید کرد! کدهای کثیف، پر از بوی بد (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 به درستی عمل کند."

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

نکته :

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

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

SOLID چیست

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

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

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

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

SOLID چیست

اگر می‌خواهید بیشتر بدانید : 

نتیجه گیری

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

چه امتیازی به این مقاله می دید؟
نویسنده زهرا فرحمند
ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :

 

نظرات کاربران

علی

سلام

ممنون از مقاله مفیدتون واقعا به کارم اومد
ولی بنظرم مثال اخر اشتباه بیان شده چون داره متدی که از والد به ارث برده شده رو override میکنه

فائقه نامور

سلام
ممنون از توجه و همراهی شما
موردی که اشاره فرمودید به تیم تولید محتوا انتقال داده می شود.

مجید زارع

سلام خدا قوت.. ممنونم بابت مقاله خوبتان
یک سوالی که پیش می آید این است که اگر بتوانیم این دو کلاس را جای یکدیگر استفاده کنیم دیگر نیاز به کلاس فرزند نیست و می توانیم از کلاس والد در همه جا استفاده کنیم پس چرا کلاس فرزند را بنویسیم؟
لطفا این سوال من را سریع جواب دهید. برام دغدغه فکری شده

نازنین کریمی مقدم

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

امین کریمی

ممنون از مقالات خوبتون
البته به نظرم این مقاله خیلی میتونه کامل تر بشه تا بهتر بشه این اصل رو درک کرد
منظورتون از مشکلات scalingچی هست میشه توضیح بدید؟

Amirhosein karimi

سلام ،
ممنون از مقالات خوبی که منتشر می کنید.
مثالی که زدید فکر میکنم اشتباه
چون ما رفتار متد extract در کلاس SecondryEmailExtratctor بازنویسی ( override ) کردیم و از کلاس SecondryEmailExtratctor نمیتونم رفتار متد extract پدر را داشته باشیم .

مجید زادگی

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

زهرا فرحمند

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