اصول طراحی SOLID در #C (قسمت دوم)

در مطلب قبلی توضیحات در مورد اصول SOLID داده و به تشریح اصل مسئولیت واحد (Single Responsibility Principle) پرداختیم اکنون در ادامه میخواهیم اصل Open/Closed را بررسی کنیم.
Open/Closed Principle
این دومین اصل از اصول SOLID است که به شرح زیر تعریف می شود.
یک کلاس یا ماژول در نرم افزار باید برای توسعه باز اما برای اصلاح بسته شود.
اگر کلاسی نوشتهایم، باید آنقدر انعطافپذیر باشد که تا زمانی که باگی وجود نداشته باشد، آن را تغییر ندهیم (برای اصلاح بسته شود) اما بتوان با افزودن کد جدید (بدون تغییر کد موجود)، یک ویژگی جدید اضافه کرد.
این اصل می گوید که باید امکان گسترش عملکرد در کلاس ها بدون تغییر کد موجود در کلاس ها وجود داشته باشد. یعنی میتوان رفتار نرمافزار را بدون تغییر در پیادهسازی هستهای موجود گسترش داد. اساساً بیان می کند که کلاس ها یا کدهای خود را به گونه ای طراحی کنید که برای افزودن ویژگی های جدید به نرم افزار، کد جدیدی را بدون نیاز به تغییر کد موجود اضافه کنید. تغییر نکردن کد موجود این مزیت را دارد که باگ های جدیدی را در کدهایی که از قبل کار می کنند خلق نمی کنید. باز کردن برای توسعه به این معنی است که شما باید پیاده سازی کد خود را به گونه ای طراحی کنید که بتوانید از ارث بری برای پیاده سازی عملکرد جدید در برنامه خود استفاده کنید. طراحی شما باید به گونه ای باشد که به جای تغییر کلاس موجود باید یک کلاس جدید که از کلاس پایه مشتق شده است اضافه کنید و یک کد جدید به این کلاس مشتق شده اضافه کنید. برای وراثت، باید به جای وراثت کلاس، به وراثت از طریق Interface نگاه کنید. اگر کلاس مشتق شده به پیاده سازی در کلاس پایه بستگی دارد، در این صورت یک وابستگی محکم بین کلاس پایه و مشتق شده ایجاد میکنید. با Interface ، می توانید ویژگی های جدیدی را با افزودن یک کلاس جدید ارائه کنید که این Interface را بدون تغییر Interface و کلاس های موجود دیگر پیاده سازی می کند. این Interface همچنین اتصال سست بین کلاس هایی را که Interface را پیاده سازی می کنند، فعال می کند.
به کد زیر که کلاسی برای تولید گزارش در قالب HTML است توجه کنید :
public class Report
{
public bool GenerateReport()
{
//Code to generate report in HTML Format
return true;
}
}
در ابتدا، لازم بود که یک گزارش فقط در قالب HTML ایجاد شود، بنابراین این کد به خوبی کار می کرد. اکنون یک الزام دارید که گزارش در هر دو فرمت HTML و JSON مورد نیاز است. بنابراین اکنون کد اصلاح شده طبق کلاس فوق به این شکل خواهد بود.
public class Report
{
public bool GenerateReport()
{
//Code to generate report in HTML Format
//Code to generate report in JSON Format
return true;
}
}
ما کدی را تغییر دادیم که برخلاف اصل Open/Closed است که بیان میکند کلاس باید گسترش یابد و تغییر داده نشود. بیایید کلاس را مطابق با اصل Open/Closed در SOLID تغییر دهیم. کد اصلاح شده طبق اصل Open/Closed به شرح زیر است :
public interface IGenerateReport
{
bool GenerateReport();
}
public class GenerateHTMLReport : IGenerateReport
{
public bool GenerateReport()
{
//Code wot Generate HTML Report
return true;
}
}
در کد بالا، ما از وراثت Interface استفاده کرده و یک Interface برای تولید گزارش اضافه کرده ایم. ما Interface را در کلاس GenerateHTMLReport برای اضافه کردن کد برای تولید گزارشها در قالب HTML پیادهسازی کردیم و این مطابق با الزامات SOLID خوب است. اکنون طبق نیاز جدید برای تولید گزارش در قالب JSON نیز تغییرات کد زیر را انجام خواهیم داد.
public interface IGenerateReport
{
bool GenerateReport();
}
public class GenerateHTMLReport : IGenerateReport
{
public bool GenerateReport()
{
//Code wot Generate HTML Report
return true;
}
}
public class GenerateJSONReport : IGenerateReport
{
public bool GenerateReport()
{
//Code to Generate JSON Report
return true;
}
}
همانطور که در بالا می بینید برای اضافه کردن ویژگی های اضافی به جای تغییر کد موجود، کد موجود را با اضافه کردن یک کلاس جدید (GenerateJSONReport) که رابط IGenerateReport را پیاده سازی می کند، برای افزودن کد برای تولید گزارش در قالب JSON گسترش داده ایم. اکنون کد فراخوانی می تواند هر دو کلاس را برای تولید گزارش در فرمت HTML و JSON فراخوانی کند.
مزایا :
- ارث بری از طریق اینترفیس به دستیابی به اتصال سست بین کلاس هایی که آن اینترفیس را پیاده سازی می کنند کمک می کند.
- برای افزودن یک ویژگی جدید، کد موجود را تغییر نمیدهیم، بنابراین باگ های جدیدی را در کد خلق نمی کنیم.
سخن پایانی :
اصل Open/Closed یکی از مهمترین اصول طراحی در Solid است زیرا با استفاده از وراثت Interface به اتصال سست بین کلاس ها کمک می کند.
گاهی اوقات نیاز به تغییر کد موجود برای پیاده سازی ویژگی جدید وجود دارد، اما کد خود را به گونه ای طراحی کنید که برای پیاده سازی عملکردهای جدید تغییرات در کد موجود صفر یا حداقل باشد.
دیدگاهتان را بنویسید