اصل (Single Responsibility Principle (SRP

یک کلاس باید تنها یک مسئولیت داشته باشد. هر کلاس برای انجام کاری طراحی شده است؛ اینکار می‌تواند نگهداری وضعیت یک اپلیکیشن باشد یا حتی می‌تواند در حالت پیچیده‌تر یک resource-intensive processing باشد. به هر حال اگر یک کلاس برای انجام چندین کار در نظر گرفته شود، در مقیاس بزرگ باعث بروز مشکلاتی در سیستم خواهد شد.

کلاس زیر را در نظر بگیرید:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class SalesReporter
{
    public string Between(DateTime start, DateTime end)
    {
        if (!User.Identity.IsAuthenticated)
            throw new Exception("not allowed!");
        
        // get sales from db
        var sales = this.GetSalesBetween(start, end);
        // return result
        return this.Format(sales);
    }
    public decimal GetSalesBetween(DateTime start, DateTime end)
    {
        var sum = SalesDatasource.GetSales()
            .Where(s => s.CreatedDate.Date >= start.Date &&
                        s.CreatedDate.Date <= end)
            .Sum(s => s.Charge);
        return (sum / 100);
    }
    public string Format(decimal sales)
    {
        return $"<h1>{sales}</h1>";
    }
}

 

 

 

کلاس فوق قرار است مجموع فروش در بین دو بازه‌ی تاریخ را برایمان در قالب یک تگ HTML نمایش دهد. اما مشکل اینجاست که این کلاس چندین بار اصل SRP را نقض کرده است زیرا چندین مسئولیت به آن واگذار شده است.

اولین مورد را در خط ۵ مشاهده می‌کنید؛ در واقع بررسی وضعیت لاگین بودن وظیفه‌ی لایه‌ی‌ اپلیکیشن است و نباید درون این کلاس انجام شود؛ در نتیجه این قسمت را حذف خواهیم کرد.

مورد دوم نیز واکشی اطلاعات از دیتابیس است که درون این کلاس و توسط متد GetSalesBetween انجام شده است؛ این مورد نیز بهتر است به یک repository و یا سرویس دیگر واگذار شود.

مورد آخر نیز نمایش خروجی به صورت HTML است؛ این مورد نیز بهتر است توسط یک اینترفیس مهیا شود؛ در این حالت این مصرف‌کننده کلاس SalesReporter است که تصمیم خواهد گرفت خروجی با چه قالبی تهیه شود.

 

 

با در نظر گرفتن موارد فوق، شکل نهایی کلاس SalesReporter به اینصورت خواهد بود:

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SalesReporter
{
    private readonly ISalesRepository _salesRepository;
    public SalesReporter(ISalesRepository salesRepository)
    {
        _salesRepository = salesRepository;
    }
    public object Between(DateTime start, DateTime end,
                          ISalesOutput formatter)
    {
        // get sales from db
        var sales = _salesRepository.GetSalesBetween(start, end);
        // return result
        return formatter.Output(sales);
    }
}

 

 

 

همانطور که مشاهده می‌کنید حتی تعیین خروجی نیز در اختیار مصرف‌کننده کلاس فوق قرار گرفته است؛ ممکن است در شرایطی نیاز داشته باشید خروجی JSON یا XML تولید کنید برای اینکار کافی است اینترفیس ISalesOutput را برای خروجی موردنظرتان تهیه کنید.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top