آموزش برنامه نویسیزبان های برنامه نویسیمباحث عمومیمهندسی نرم افزارنرم افزار

تشریح قوانین SOLID در برنامه نویسی

solid-principles

SOLID دربرگیرنده ی اصولی در برنامه نویسی شیء گرایی است که در اوایل سال ۲۰۰۰ توسط مهندسی به نام Robert Martin که تحت عنوان Uncle Bob یا «عمو باب» شناخته می‌شود ابداع شد.

وقتی این اصول به درستی در کنار یکدیگر به کار گرفته شوند، این امکان را به برنامه نویس یا توسعه‌دهنده می‌دهند تا با سهولت بیشتری به توسعه نرم افزارهای خود بپردازد. علاوه بر این، به کارگیری اصول SOLID این امکان را به برنامه نویسان خواهد داد تا با رویکردی چابک به توسعه نرم افزارهای خود پرداخته، از مرتکب شدن اشتباهات کوچک جلوگیری کنند و در صورت نیاز هم به سادگی اقدام به بازنویسی کدهای خود کنند.

SOLID مخفف اصطلاحات زیر است:

S: Single Responsibility
O: Open / Closed
L: Liskov Substitution
I: Interface Segregation
D: Dependency Inversion

Single Responsibility Principle
این قانون که به طور خلاصه SRP نیز نامیده می‌شود، حاکی از آن است که یک کلاس باید صرفاً یک وظیفه بیشتر نداشته باشد که در این صورت، کلاس‌ها فقط و فقط به خاطر ایجاد تغییر در وظیفه‌ای که انجام می‌دهند دستخوش تغییر خواهند شد نه چیز دیگر! کلاس‌ها می‌توانند فیچرهای مختلفی داشته باشند اما تمامی آن‌ها باید مربوط به یک حوزه بوده و مرتبطبه هم باشند که در نهایت با محترم شمردن چنین قانونی، برنامه‌نویسان دیگر قادر نخواهند بود تا کلاس‌های اصطلاحاً همه‌فن‌حریف بنویسند.

Open-Closed Principle
هر کلاسی باید برای توسعه یافتن قابلیت‌هایش اصطلاحاً Open بوده و دست برنامه‌نویس برای افزودن فیچرهای جدید به آن باز باشد اما اگر وی خواست تا تغییری در کلاس ایجاد کند، چنین امکان باید Closed بوده و او اجازهٔ چنین کاری را نداشته باشد. فرض کنیم نرم‌افزاری نوشته‌ایم که دارای چندین کلاس مختلف است و نیازهای اپلیکیشن‌مان را مرتفع می‌سازند اما به جایی رسیده‌ایم که نیاز داریم قابلیت‌های جدید به برنامهٔ خود بیفزاییم. بر اساس این قانون، دست‌مان برای تغییر یا بهتر بگوییم افزودن فیچرهای جدید به کلاس مد نظر باز است در حالی که این قابلیت‌های جدید باید در قالب افزودن کدهای جدید صورت پذیرد نه ریفکتور کردن و تغییر کدهای قبلی!

برای روشن‌تر شدن این مسأله مثالی می‌زنیم. پیش از این با مفهوم وراثت در برنامه‌نویسی آشنا شدیم. فرض کنیم کلاسی داریم تحت عنوان BankAccount که دو کلاس دیگر تحت عناوین SavingAccount و InverstmentAccount از آن ارث‌بری می‌کنند و قصد داریم کلاس جدیدی تحت عنوان CurrentAccount ایجاد کنیم که از BankAccount ارث‌بری می‌کند اما این کلاس جدید دارای یکسری قابلیت‌هایی است که در کلاس والد دیده نشده‌اند که در چنین شرایطی به جای آنکه قابلیت‌های مد نظر جدید را به کلاس والد بیفزاییم، نیاز خود را از طریق افزودن قابلیت‌های جدید در همان کلاس فرزند عملی می‌کنیم. به عبارتی، هرگز دست به تغییر کدهای موجود نزده و قانون Open/Closed را هم به رسمیت شناخته‌ایم به طوری که کلاس مد نظرمان برای توسعه باز است اما برای اِعمال هر گونه تغییری بسته است.

Liskov Substitution Principle
این اصل حاکی از آن است که کلاس‌های فرزند باید آن‌قدر کامل و جامع از کلاس والد خود ارث‌بری کرده باشند که به سادگی بتوان همان رفتاری که با کلاس والد می‌کنیم را با کلاس‌های فرزند نیز داشته باشیم به طوری که اگر در شرایطی قرار گرفتید که با خود گفتید کلاس فرزند می‌تواند تمامی کارهای کلاس والدش را انجام دهد به جزء برخی موارد خاص، اینجا است که این اصل از SOLID را نقض کرده‌اید.

Interface Segregation Principle
پیش از این هم گفتیم که اینترفیس‌ها فقط مشخص می‌کنند که یک کلاس از چه متدهایی حتماً باید برخوردار باشد. در همین راستا و بر اساس این قانون، چندین اینترفیس تک‌منظوره به مراتب بهتر است از یک اینترفیس چندمنظوره است به طوری که اگر یک اینترفیس چندمنظورهٔ کامل و جامع داشته باشیم و سایر کلاس‌های ما از آن اصطلاحاً implementsکنند،‌ در چنین صورتی ممکن است برخی خصوصیات، متدها و رفتارها را به برخی کلاس‌هایی که اصلاً نیازی به آن‌ها ندارند تحمیل کنیم اما اگر از چندین اینترفیس تخصصی استفاده کنیم، به سادگی می‌توانیم از هر اینترفیسی که نیاز داشته باشیم در کلاس‌های مد نظر خود استفاده نماییم و در صورتی هم کلاسی وجود داشت که نیاز به استفاده از چندین اینترفیس مختلف داشت، دست ما باز خواهد بود تا آن کلاس را از چندین اینترفیس implements کنیم.

Dependency Inversion Principle
درک این اصل از اصول پنج‌گانهٔ SOLID کمی دشوارتر به نظر می‌رسد و برخی تازه‌کارها آن را با Dependency Injection اشتباه می‌گیرند. به طور خلاصه، در OOP باید تمام تلاش خود را به کار بندیم تا Dependency (وابستگی) را مابین کلاس‌ها، ماژول‌ها و آبجکت‌های سطح بالا با ماژول‌های سطح پایین به حداقل برسانیم که با این کار، اِعمال تغییرات در آینده به مراتب راحت‌تر صورت خواهد پذیرفت.

نظرات