• بررسی SRP یا Single responsibility principle
بررسی SRP یا Single responsibility principle
1395/09/12 - 11:37:12 // DataBase and Design Pattern // 0 نظر // 8574 بازدید

در دو قسمت قبلی هر Principle از استانداردهای SOLID را نام بردیم و حال وقت شرح و بررسی هر یک از آنهاست . اولین و شاید بتوان گفت مهمترین آیتم همان SRP است که شرح و بررسی آن خواهیم پرداخت .

بسمه تعالی

آموزش SOLID Programming Principles - بخش سوم

در دو قسمت قبلی هر Principle از استانداردهای SOLID را نام بردیم و حال وقت شرح و بررسی هر یک از آنهاست . اولین و شاید بتوان گفت مهمترین آیتم همان SRP است که شرح و بررسی آن خواهیم پرداخت .

§ Single responsibility principle (SRP)

در عمل کاراکتر S در عبارت SOLID به دلیل همین SRP می باشد.

در عمل SRP به این معناست که هر Object باید فقط یک دلیل برای دستکاری و فقط یک وظیفه انجام داشته باشد.به عبارت دیگر، هر Object باید فقط انجام دهنده یک وظیفه و تحرک باشد. همه ما در گذشته هم چنین مفهومی را با استفاده از Method ها، Domain Model یا Business Layer پیاده سازی کرده ایم . به عنوان مثال، اگر یک عملیات Insert در دیتابیس قرار است اجرا شود، کلاس مورد نظر ما دیگر وظیفه Exception Handling نبایست داشته باشد و برای آن می بایست یک Object دیگر ایجاد و صدا زده شود.

به صورت کلی، هدف ما از پیاده سازی و رعایت قواعد SRP به طور اجمالی شرح زیر است .

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

· افزایش امکان تست پذیری از طریق ایجاد قواعد تک منظوره در روالهای کدنویسی.

· افزایش خوانایی کد و ارتقای سطح کار تیمی.

· افزایش و ساده سازی روند تعمیر پذیری کدها

شاید با عبارت Separation of Concerns یا به صورت اختصاری SOC آشنا باشید. در واقع SRP همان پیاده سازی صحیح مفاهیم SOC خواهد بود. هر Object یک وظیفه جهت انجام داشته باشد و از مخلوط شدن وظایف و بخشها جلوگیری گردد.

در ادامه بهتر است با دو مفهوم زیر آشنا شویم.

· Cohesion
· Coupling

در عمل Cohesion به معنای انسجام ماژولها و اختصاص وظایف به آنهاست و Coupling به معنای ارتباط درگیری هر ماژول با دیگری و اختلاط آنها با همدیگر میباشد.

در یک طراحی نرم افزار استاندارد، باید میزان Cohesion را بالا برده و Coupling را به حداقل برسانیم.اگر قرار باشد یک کلاس به دلایلی دستخوش تغییر گردد، باید دقیقا و دقیقا همان کلاس تغییر نماید و نیاز به دست زدن به دیگر Object ها باید در حد صفر یا در حداقل میزان ممکنه باشد. اگر قصد دارید میزان درستی پیاده سازی SRP را در کدهای خود بررسی کنید، به سراغ TDD رفته و اختصاصن از Test First Approach استفاده نمایید. در این حالت میتوان میزان و سطح پیاده سازی SRP در کدهای شما تا حدود زیادی مشخص خواهد شد.

خوب حال وقت آن است که یک برای مثال یک پروژه e-commerce را به عنوان مثال در یک وضعیت در هم بر هم و بدون پیاده سازی SRP مورد بررسی قرار دهیم.

در VS یک پروژه Console ایجاد کنید و درون آن یک فولدر به نام Model ایجاد نمایید.

  1. public class OrderItem  
  2. {  
  3.     public string Identifier { getset; }  
  4.     public int Quantity { getset; }  
  5. }  
  6. public class ShoppingCart  
  7. {  
  8.     public decimal TotalAmount { getset; }  
  9.     public IEnumerable<OrderItem> Items { getset; }  
  10.     public string CustomerEmail { getset; }  
  11. }  
  12. public enum PaymentMethod  
  13. {  
  14.     CreditCard  
  15.     , Cheque  
  16. }  
  17. public class PaymentDetails  
  18. {  
  19.     public PaymentMethod PaymentMethod { getset; }  
  20.     public string CreditCardNumber { getset; }  
  21.     public DateTime ExpiryDate { getset; }  
  22.     public string CardholderName { getset; }  
  23. }  
 
 

پس از Model به سراغ متدهایی خواهیم رفت که وظیفه دریافت سفارشات و ... را بر عهده دارند.

  1. public class Order  
  2. {  
  3.     public void Checkout(ShoppingCart shoppingCart, PaymentDetails paymentDetails, bool notifyCustomer)  
  4.     {  
  5.         if (paymentDetails.PaymentMethod == PaymentMethod.CreditCard)  
  6.         {  
  7.             ChargeCard(paymentDetails, shoppingCart);  
  8.         }  
  9.    
  10.         ReserveInventory(shoppingCart);  
  11.    
  12.         if (notifyCustomer)  
  13.         {  
  14.             NotifyCustomer(shoppingCart);  
  15.         }  
  16.     }  
  17.    
  18.     public void NotifyCustomer(ShoppingCart cart)  
  19.     {  
  20.         string customerEmail = cart.CustomerEmail;  
  21.         if (!String.IsNullOrEmpty(customerEmail))  
  22.         {  
  23.             try  
  24.             {  
  25.                 //construct the email message and send it, implementation ignored  
  26.             }  
  27.             catch (Exception ex)  
  28.             {  
  29.                 //log the emailing error, implementation ignored  
  30.             }  
  31.         }  
  32.     }  
  33.    
  34.     public void ReserveInventory(ShoppingCart cart)  
  35.     {  
  36.         foreach (OrderItem item in cart.Items)  
  37.         {  
  38.             try  
  39.             {  
  40.                 InventoryService inventoryService = new InventoryService();  
  41.                 inventoryService.Reserve(item.Identifier, item.Quantity);  
  42.    
  43.             }  
  44.             catch (InsufficientInventoryException ex)  
  45.             {  
  46.                 throw new OrderException("Insufficient inventory for item " + item.Sku, ex);  
  47.             }  
  48.             catch (Exception ex)  
  49.             {  
  50.                 throw new OrderException("Problem reserving inventory", ex);  
  51.             }  
  52.         }  
  53.     }  
  54.    
  55.     public void ChargeCard(PaymentDetails paymentDetails, ShoppingCart cart)  
  56.     {  
  57.         PaymentService paymentService = new PaymentService();  
  58.    
  59.         try  
  60.         {  
  61.             paymentService.Credentials = "Credentials";  
  62.             paymentService.CardNumber = paymentDetails.CreditCardNumber;  
  63.             paymentService.ExpiryDate = paymentDetails.ExpiryDate;  
  64.             paymentService.NameOnCard = paymentDetails.CardholderName;  
  65.             paymentService.AmountToCharge = cart.TotalAmount;  
  66.    
  67.             paymentService.Charge();  
  68.         }  
  69.         catch (AccountBalanceMismatchException ex)  
  70.         {  
  71.             throw new OrderException("The card gateway rejected the card based on the address provided.", ex);  
  72.         }  
  73.         catch (Exception ex)  
  74.         {  
  75.             throw new OrderException("There was a problem with your card.", ex);  
  76.         }  
  77.    
  78.     }  
  79. }  
  80.    
  81. public class OrderException : Exception  
  82. {  
  83.     public OrderException(string message, Exception innerException)  
  84.         : base(message, innerException)  
  85.     {  
  86.     }  
  87. }  
 

پس از کلاس Order یک فولدر به نام Services ساخته و بخشهای Inventory و Payment را اضافه مینماییم.

  1. public class InventoryService  
  2. {  
  3.     public void Reserve(string identifier, int quantity)  
  4.     {  
  5.         throw new InsufficientInventoryException();  
  6.     }  
  7. }  
  8.    
  9. public class InsufficientInventoryException : Exception  
  10. {  
  11. }  
  12. public class PaymentService  
  13. {  
  14.     public string CardNumber { getset; }  
  15.     public string Credentials { getset; }  
  16.     public DateTime ExpiryDate { getset; }  
  17.     public string NameOnCard { getset; }  
  18.     public decimal AmountToCharge { getset; }  
  19.     public void Charge()  
  20.     {  
  21.         throw new AccountBalanceMismatchException();  
  22.     }  
  23. }  
  24.    
  25. public class AccountBalanceMismatchException : Exception  
  26. {  
  27. }  
 دقت کنید که این متدها کار خاصی به جز باز گرداندن Exception انجام نخواهند داد.

حال وقت آن است ببینیم ایراد کدهای ایجاد شده چیست و چگونه میتوان بر اساس قواعد SRP آنرا تصحیح نمود. در بخش بعدی به بررسی این موضوع خواهیم پرداخت.

 
علی کلاهدوزان
معرفی نویسنده : علی کلاهدوزان

سلام بر دوستان ،
شاید رایج است به عنوان پروفایل کاربر ، چند خطی راجع به خودم بنویسم ، ولی وضعیت کاری و سوابق من با یک جستجوی ساده در گوگل مشخص خواهد شد ، لذا سرتان را با مطالب بی مورد به درد نیاورم بهتر است . اگر نکته خاصی لازم بود بدانید در قسمت "ایلیا سافت در یک نگاه" به احتمال زیاد یافت خواهد شد . جزئیات بیشتر را سوال کنید ، آدرس ایمیل Ali@Kolahdoozan.com همیشه جوابگوی شماست .امیدوارم از مطالب سایت استفاده کرده باشید . شاد و پیروز باشید .

امتیاز به مطلب
           
نظرات کاربران
ارسال نظر