با عرض سلام و احترام.
پیشاپیش از شما دوست عزیز و گرامی، بابت وقتی که برای مطالعه ی این مطلب خواهید گذاشت، سپاسگزارم.
تقاضا دارم، در صورت مشاهده ی اشتباه متنی یا محتوایی، به اینجانب اطلاع دهید تا (ضمن کمک به یادگیری بنده) در اسرع وقت برای اصلاح متن اقدام نمایم.
شماره ی تماس:
09215149218
نشانی پست الکترونیکی:
RezaQadimi.ir@Gmail.com
آدرس سایت ها:
https://Reza-Qadimi.ir - https://WannaDate.ir
هدف من در این مقاله، آشنایی شما با چهارمین اصل از اصول .S.O.L.I.D، یعنی DIP یا Dependency Inversion Principle است.
اصل DIP بیان میکند:
ماژول (کلاس) سطح بالا، نباید به ماژول های سطح پایین تر وابستگی داشته باشند، و وابستگی هر دو آن ها، باید به abstraction باشد. همینطور باید گفت abstraction نباید به جزئیات وابستگی داشته باشد و این جزئیات هستند که به abstraction وابستگی دارند.
بنابراین میتوان گفت، این اصل از سه جز تشکیل شده است:
به این مثال توجه کنید:
public class SalaryCalculator : object { public SalaryCalculator() : base() { } public decimal CalculateSalary(int hoursWorked, decimal hourlyRate) { decimal result = hoursWorked * hourlyRate; return result; } }
نکته: هر چند میتوانیم تابع "CalculateSalary" را به این صورت بنویسیم:
public decimal CalculateSalary (int hoursWorked, decimal hourlyRate) => hoursWorked * hourlyRate ;
اما از آنجایی که در زمان دیباگ، امکان trace کردن روند محاسبه و نتیجه ی نهایی را نداریم، از این امکان استفاده نمیکنیم.
public class EmployeeDetails : object { public EmployeeDetails() : base() { } public int HourlyRate { get; set; } public int HoursWorked { get; set; } public decimal GetSalary() { SalaryCalculator salaryCalculator = new(); decimal result = SalaryCalculator.CalculateSalary (hoursWorked: HourseWorked, hourlyRate: HourlyRate); return result; } }
مثال بالا، نمونه ی بارز نقض DIP ست، چرا که (با این روش پیاده سازی) کلاس سطح بالای ما (یعنی "EmployeeDetails")، به کلاس سطح پایین ما (یعنی "SalaryCalculator") وابسته شده است.
اما چگونه میتوان این مشکل را برطرف کرد؟
بیایید دوباره اصل Dependency Inversion را با هم مرور کنیم:
کلاس سطح بالای ما، نباید به کلاس های سطح پایین وابستگی داشته باشد، و وابستگی هر دوی آن ها باید به "abstraction" باشد.
public interface ISalaryCalculator { decimal CalculateSalary(int hoursWorked, decimal hourlyRate); }
public class SalaryCalculator : object, ISalaryCalculator { public SalaryCalculator() : base() { } public decimal CalculateSalary(int hoursWorked, decimal hourlyRate) { decimal result = hoursWorked * hourlyRate; return result; } }
public class EmployeeDetails : object { public EmployeeDetails(ISalaryCalculator salaryCalculator) : base() { SalaryCalculator = salaryCalculator; } public int HourlyRate { get; set; } public int HoursWorked { get; set; } public ISalaryCalculator SalaryCalculator { get; } public decimal GetSalary() { decimal result = SalaryCalculator.CalculateSalary (hoursWorked: HourseWorked, hourlyRate: HourlyRate); return result; } }
همانطور که میبینید، وابستگی ما دیگر به کلاس "SalaryCalculator" نیست، و به اینترفیس "ISalaryCalculator" معکوس (یا اصطلاحا invert) شده است. این بدان معناست که ما دیگر با این که چه کسی متد "CalculateSalary" را پیاده سازی کرده است، کاری نداریم و صرفا با لایه ی abstract آن در ارتباط هستیم.
معرفی:
رضا قدیمی هستم. برنامه نویس و دانش آموزِ حوزه ی وب، بسیار مشتاق در یادگیری مفاهیم و اطلاعات جدید در این حوزه.