اصول SOLID در برنامه نویسی - اصل L
اصول SOLID در برنامه نویسی
اصل جایگزینی لیسکوف (Liskov Substitution Principle) در SOLID
مقدمه
اصل جایگزینی لیسکوف (LSP) یکی از پنج اصل SOLID است که توسط باربارا لیسکوف معرفی شد. این اصل به ما کمک میکند تا از وراثت (Inheritance) بهدرستی در طراحی شیءگرا استفاده کنیم. طبق این اصل، اگر کلاسی مشتقشده (Derived Class) از یک کلاس پایه (Base Class) ارثبری کند، باید بتوان آن را بهجای کلاس پایه استفاده کرد، بدون اینکه رفتار برنامه تغییر کند یا خطایی رخ دهد. نقض این اصل میتواند به کدهای شکننده و غیرقابلاعتماد منجر شود.
مدرس بهمن آبادی، مدرس دوره جامع برنامهنویسی وب، در بخشهای سی شارپ پیشرفته و برنامه نویسی وب این اصل را با مثالهای عملی و ساده توضیح میدهد. او تأکید میکند که رعایت LSP به خصوص در پروژههای بزرگ وب، مانند سیستمهای مدیریت محتوا یا APIهای پیچیده، از اهمیت بالایی برخوردار است.
مفهوم اصل LSP
LSP به ما میگوید که:
- متدهای کلاس فرزند نباید قراردادهای کلاس والد (مانند پیششرطها، پسشرطها یا رفتار مورد انتظار) را نقض کنند.
- کلاس فرزند نباید انتظار ورودیهای محدودتر یا خروجیهای متفاوت نسبت به کلاس والد داشته باشد.
- استفاده از شیء کلاس فرزند بهجای شیء کلاس والد نباید باعث رفتار غیرمنتظره یا خطا شود.
به عنوان مثال، اگر یک کلاس پایه برای پرندگان داشته باشیم که متدی برای پرواز دارد، کلاسی مانند پنگوئن (که نمیتواند پرواز کند) نباید مستقیماً از این کلاس ارثبری کند، زیرا نقض رفتار مورد انتظار کلاس پایه است.
نقض اصل LSP در C#
برای درک بهتر، ابتدا یک مثال از نقض LSP ارائه میدهیم:
مثال 1: نقض LSP
فرض کنید کلاسی برای پرندگان داریم که متدی برای پرواز تعریف میکند:
مشکل این کد:
کلاس Penguin از Bird ارثبری کرده، اما متد Fly را با پرتاب خطا پیادهسازی کرده است. این نقض LSP است، زیرا شیء Penguin نمیتواند بهجای شیء Bird بدون ایجاد خطا استفاده شود.
متد MakeBirdFly انتظار دارد هر شیء از نوع Bird بتواند پرواز کند، اما این انتظار برای پنگوئن نقض میشود.
این طراحی شکننده است و ممکن است در بخشهای دیگر برنامه که از Bird استفاده میکنند، خطاهای غیرمنتظره ایجاد شود.
نقض LSP اغلب در پروژههای وب زمانی رخ میدهد که توسعهدهندگان بدون توجه به قراردادهای کلاس پایه، کلاسهای فرزند را پیادهسازی میکنند. مدرس بهمن آبادی توصیه میکند که قبل از استفاده از وراثت، رفتارهای مشترک بهدقت شناسایی شوند.
رعایت اصل LSP در C#
برای رفع مشکل بالا، باید طراحی را اصلاح کنیم تا کلاسها بهدرستی جایگزینپذیر باشند. میتوانیم از رابطها (Interfaces) یا کلاسهای پایهای استفاده کنیم که رفتارهای مشترک را بهدرستی مدلسازی کنند.
مثال 2: رعایت LSP
در این مثال، از رابطها برای جداسازی رفتار پرواز استفاده میکنیم:
مزایای این کد:
کلاس Penguin دیگر مجبور نیست متد Fly را پیادهسازی کند، زیرا فقط کلاسهایی که از IFlyable ارث میبرند، این رفتار را دارند.
متد MakeBirdFly فقط با اشیائی کار میکند که قابلیت پرواز دارند، بنابراین جایگزینی کاملاً امن است.
این طراحی LSP را رعایت میکند، زیرا هیچ کلاس فرندی رفتار کلاس پایه یا رابط را نقض نمیکند.
کد ماژولارتر و قابلنگهداریتر است.
مدرس بهمن آبادی دردوره جامع برنامهنویسی وب خود، این نوع طراحی را با مثالهایی از پروژههای وب نشان میدهد. او توضیح میدهد که در APIهای وب، استفاده از رابطها برای جداسازی رفتارها (مانند پردازش درخواستهای مختلف) میتواند از نقض LSP جلوگیری کند و توسعه را سادهتر کند.
مثال عملی دیگر: سیستم پرداخت
فرض کنید سیستمی برای پردازش پرداختها داریم. بدون رعایت LSP، ممکن است طراحی زیر را داشته باشیم:
نقض LSP در سیستم پرداخت
مشکل: کلاس CashPayment قرارداد کلاس پایه را نقض میکند، زیرا نمیتواند پرداخت را پردازش کند.
رعایت LSP در سیستم پرداخت
برای رعایت LSP، از رابط استفاده میکنیم:
مزایا:
هر نوع پرداخت فقط رفتارهایی را پیادهسازی میکند که واقعاً پشتیبانی میکند.
متد Process فقط با اشیائی کار میکند که رابط IPaymentProcessor را پیادهسازی کردهاند.
این طراحی LSP را رعایت میکند و از خطاهای غیرمنتظره جلوگیری میکند.
مدرس بهمن آبادی در دوره جامع برنامهنویسی وب خود به مثالهایی مشابه این اشاره میکند، بهویژه در بخش طراحی APIهای وب که نیاز به پردازش انواع مختلف درخواستها (مانند پرداختها) دارند. او تأکید میکند که استفاده از رابطها و جداسازی مسئولیتها باعث میشود کد شما انعطافپذیرتر و قابلتست باشد.
دوره جامع برنامهنویسی وب بهمن آبادی
مهندس بهمن آبادی در دوره جامع برنامهنویسی وب خود، اصل LSP را بهعنوان یکی از پایههای طراحی شیءگرا معرفی میکند. او با مثالهایی از پروژههای وب، مانند سیستمهای مدیریت کاربران یا پردازش تراکنشها، نشان میدهد که چگونه نقض LSP میتواند به کدهای پیچیده و غیرقابلنگهداری منجر شود. او به دانشجویان توصیه میکند که:
از رابطها برای تعریف قراردادهای واضح استفاده کنند.
رفتارهای خاص هر کلاس را بهدرستی مدلسازی کنند تا از نقض قراردادهای کلاس پایه جلوگیری شود.
در پروژههای وب، از الگوهایی مانند Strategy یا Factory برای مدیریت انواع مختلف اشیاء استفاده کنند.
به عنوان مثال، او ممکن است سناریویی مشابه سیستم پرداخت بالا را در دوره خود بررسی کند و نشان دهد که چگونه با استفاده از رابطها و معماری تمیز، میتوان APIهایی طراحی کرد که بهراحتی گسترش یابند و LSP را رعایت کنند.
نتیجهگیری
اصل جایگزینی لیسکوف (LSP) یکی از اصول کلیدی SOLID است که به ما کمک میکند تا از وراثت بهدرستی استفاده کنیم و کدهایی قابلاعتماد و انعطافپذیر بنویسیم. با استفاده از رابطها و جداسازی رفتارها، میتوانیم از نقض این اصل جلوگیری کنیم و جایگزینی کلاسهای فرزند بهجای کلاسهای والد را بدون مشکل تضمین کنیم.
مهندس بهمن آبادی در دوره جامع برنامهنویسی وب خود، این اصل را با مثالهای کاربردی و مرتبط با توسعه وب توضیح داده است. او با تأکید بر استفاده از رابطها و الگوهای طراحی، به دانشجویان نشان میدهد که چگونه میتوانند سیستمهای مقیاسپذیر و قابلنگهداری طراحی کنند. اگر به دنبال یادگیری عمیق اصول SOLID و کاربرد آنها در پروژههای واقعی هستید، دورههای ایشان و مطالعه مثالهای بالا میتوانند نقطه شروع عالی باشند.
منابع:
(SOLID Principles in C#: Liskov Substitution Principle with Examples)
(Clean Code and Design Patterns in .NET)