مقدمه:
در دنیای برنامهنویسی شیءگرا، بدون در نظر گرفتن زبان برنامه نویسی، طراحی مناسب بستر نرمافزار نقش بسیار کلیدی در توسعهی کدهای قابل نگهداری و توسعهپذیر بازی می کند. اصول SOLID مجموعهای از پنج اصل طراحی هستند که به توسعهدهندگان کمک قابل توجهی میکنند تا نرمافزارهایی منعطف، پایدار و مقیاسپذیر ایجاد کنند. هر یک از حروف عبارت SOLID برگرفته از حرف اول یک عبارتی است که بیانگر رسالت هر کدام از آن اصول است.
در این مطلب، به طور خلاصه، این اصول را بررسی خواهیم کرد.
۱. اصل تک مسئولیتی (Single Responsibility Principle - SRP)
اصل تک مسئولیتی بیان میکند که هر کلاس باید فقط یک دلیل برای تغییر داشته باشد. این بدان معناست که هر کلاس باید تنها یک وظیفهی مشخص را بر عهده داشته باشد و از انجام چندین کار مختلف اجتناب کند. در این صورت است که اگر در طول حیات نرم افزار، بخشی نیاز به تغییر داشته باشد، مستقیم به سراغ کلاسی خواهیم رفت که به طور مستقل و یگانه وظیفه آن کار را به عهده دارد، و تنها در همان قسمت تغییرات را اعمال خواهیم کرد.
مثال: اگر کلاسی مسئول مدیریت دادههای یک کاربر و همچنین نمایش اطلاعات او در UI باشد، این کلاس دو مسئولیت دارد. بهتر است این وظایف را در دو کلاس جداگانه تفکیک کنیم. چرا که نمایش اطلاعت در UI ممکن است در بستر های مختلف صورت گیرد و امروز نیاز داریم که اطلاعات را در بستر وب ارایه کنیم و روز دیگر نیاز پیدا خواهیم کرد که اطلاعات را در بستر تلفن های همراه عرضه کنیم، پس نباید مجبور شویم در بخش های مختلف برنامه تغییرات ایجاد کنیم.
۲. اصل باز-بسته (Open-Closed Principle - OCP)
طبق این اصل، کلاسها باید برای توسعه باز و برای تغییر بسته باشند. این بدان معناست که بدون تغییر کدهای موجود، باید بتوان ویژگیهای جدیدی به سیستم اضافه کرد.
مثال: به جای تغییر مستقیم یک کلاس، میتوان با استفاده از وراثت یا پیادهسازی اینترفیسها رفتار جدیدی به کلاسها اضافه کرد.
۳. اصل جایگزینی لیسکوف (Liskov Substitution Principle - LSP)
این اصل بیان میکند که هر زیرکلاس باید بتواند بدون تغییر درستی برنامه، جایگزین کلاس والد خود شود.
مثال: اگر کلاس پایهی «پرنده» یک متد پرواز دارد، زیرکلاسی مانند «شترمرغ» که قادر به پرواز نیست، نباید از این کلاس ارثبری کند؛ بلکه باید به گونهای دیگر طراحی شود.
در دیاگرام ریر اصل لیسکوف رعایت نشده است:
ماشین و دوچرخه هر دو وسیله نقلیه هستند، اما دوچرخه نمیتواند جایگزین وسیله نقلیه شود زیرا دوچرخه فاقد موتور است.
اصلاح دیاگرام فوق طبق اصل جایگزینی لیسکوف:
وسیله نقلیه (Vehicle) یک تعمیم برای وسیله نقلیه موتوری و غیر موتوری است. و اکنون هم ماشین (Car) و هم دوچرخه (BiCycle) میتوانند جایگزین کلاس بیس و رابطها شوند.
۴. اصل تفکیک رابط (Interface Segregation Principle - ISP)
این اصل بیان میکند که نباید یک اینترفیس بزرگ و کلی ایجاد کرد که کلاسهای مختلف مجبور باشند متدهایی را پیادهسازی کنند که به آنها نیازی ندارند. به جای این کار، باید اینترفیسها را به بخشهای کوچکتر و اختصاصیتر تقسیم کنیم.
مثال: اگر یک اینترفیس شامل متدهای print() و
scan() باشد، اما برخی کلاسها فقط نیاز به print() دارند، بهتر است اینترفیسهای جداگانهای برای چاپ و اسکن ایجاد شود.
به مثال زیر دقت کنید:
آیا اصلا احتیاجی هست که دایره متد HowManySides را داشته باشد؟ یا باید خطای NoImplementedException برگرداند.
چنین راه حلی همیشه نادرست است. ساختار نشان می دهد که هنوز متدی برای پیاده سازی وجود دارد. لذا این ساختار گویای این مطلب نیست که یک شیء خاص، در اینجا دایره، عملکردی که توسط رابط توصیف شده است را ندارد. در این مثال ساده تغییرات به شکل زیر ایجاد می شوند تا مشکل را مرتفع کنند:
۵. اصل وابستگی وارون (Dependency Inversion Principle - DIP)
اصل وابستگی وارون بیان میکند که ما باید وابستگی را به سمت اینترفیسها و انتزاعها هدایت کنیم، نه به سمت پیادهسازیهای خاص. این کار باعث انعطافپذیری بیشتر و کاهش وابستگیهای سخت بین کلاسها میشود.
مثال: به جای آنکه یک کلاس مستقیماً به یک کلاس دیگر وابسته باشد، میتواند به یک اینترفیس وابسته شود و کلاسهای مختلف آن اینترفیس را پیادهسازی کنند.
نتیجهگیری:
رعایت اصول SOLID در طراحی شیءگرا منجر به کدهای خواناتر، توسعهپذیرتر و منعطفتر میشود. این اصول به ما کمک میکنند که از پیچیدگیهای غیرضروری جلوگیری کرده و نرمافزاری مقیاسپذیر و پایدار ایجاد کنیم. با رعایت این اصول، کدهای ما کمتر دچار تغییرات ناگهانی شده و بهراحتی قابل گسترش خواهند بود.