اصل Single Responsibility چیست؟

تو دنیای برنامه نویسی و البته شیء گرایی SOLID مجموعه ی از 5 قاعده (اصل) ابتدایی شامل

  • Single responsibility
  • Open-closed
  • Liskov substitution
  • Interface segregation
  • Dependency inversion

هست و توسط رابرت مارتین در اوایل سال 2000 معرفی شده و
شاید اکثرا با تعاریف این اصول آشنا باشین (درست یا غلط)  ولی بشخصه زیاد با مثال های که تو تاپیک های از این دست زده میشه مشکل دارم(انواع و اقسام اشکال هندسی) 
قصد دارم این اصول رو با مثال های نزدیکتر با دنیای واقعی شرح بدم منظور مثال های از برنامه های تجاری(البته اگه پیدا کنم)
قبل از شروع از اساتید و دوستانی که (شاید) این پست رو میبینن درخواست میکنم در صورت خطا (برداشت غلط و…) تو مطالب و مثال های ارائه شده منو راهنمایی کنن.

اصل Single responsibility
تعریف کردن این اصل خیلی راحته ولی انجامش در عمل سخته و تقریبا میشه گفت مثل امنیت همیشه %100 نیست.
این اصل میگه هر کلاس فقط باید یک مسئوليت داشته و همچنیا میگه هر کلاس باید یک دلیل برای تغییر داشته باشه همونطور که گفتم راحت تعریف میشه ولی انجام و پیاده سازی درستش تقریبا سخته.
در صورتی که این اصل خوب انجام بشه فواید زیر رو برای ما داره

  • پیچیدگی کلاس ها کم میشه
  • خوانایی کلاس بالا میره
  • Coupling رو کم میکنه
  • کلاس ها راحتر تست میشن
  • قابلیت استفاده مجدد کدها افزایش پیدا میکنه

و…
با توجه به اون تعریف اولیه که هر کلاس یه مسئوليت داشته باشه من کلاس Customer رو که شامل متدهای Print و Save و CalculateSalary باشه رو ناقض اصل Single responsibility نمیدوم چون میگم مسئوليت این کلاس انجام کارهای مشتریه ولی یه قسمت دیگه ی تعریف میگه هر کلاس باید یک دلیل برای تغییر داشته باشه به تغییرات احتمالی کلاس  Customer توجه کنید

  • درصد مالیات تو متد CalculateSalary بالا بره
  • متد Save بجای Sql Server روی Oracle انجام بشه

و…
نتیجه n دلیل برای تغییر تو این کلاس داریم پس برای رعایت SRP میایم کلاس های CustomerPrinter و CustomerSaver و CustomerSalaryCalculator رو تعریف میکنیم.
و اما برای مثال عملی فرض کنید میخواهیم کلاسی تعریف کنیم که کاربر بتونه تنظیمات برنامه رو باهاش عوض کنه البته قبلش کاربر احراز هویت بشه.

public class UserSettingService
{
  public void changeEmail(User user)
  {
	if(checkAccess(user))
	{
	   //دادن اجازه ی تغییر
	}
  }
  public boolean checkAccess(User user)
  {
	//برسی معتبر بودن کاربر
  }
}

این کلاس 2 تا مسئوليت داره 1-احراز هویت 2-تغییر تنظیمات برنامه
این کلاس چندین دلیل برا تغییر داره 1-عوض کردن روش احراز هویت شدن 2-عوض کردن مثلا روش تائید عوض کردن ایمیل و…

برای رعایت کردن اصل SRP تو این مثال کد Refactor شده به شکل زیر میشه

public class UserSettingService
{
  public void changeEmail(User user)
  {
	if(SecurityService.checkAccess(user))
	{
	   	   //دادن اجازه ی تغییر
	}
  }
}
public class SecurityService
{
  public static boolean checkAccess(User user)
  {
	//برسی کردن دسترسی
  }
}

در واقع با تجزیه کردن کلاس UserSettingService به دو کلاسUserSettingService و SecurityService ما کلاس های داریم که تنها یک مسئوليت دارن.
در آخر ذکر این نکته مهمه که برا فراگیری درست این اصول و کلا برنامه نویسی نگاه کردن به کد دیگران الزامیه همنطور که جناب Scott Hanselman ذکر کردن

Reading to Be a Better Developer

پس خوندن (نه کپی پیست کردن) چیز مهمیه که خالق ASP.NET MVC (البته یکی از اونا) میگه من کد دیگرون رو میخونم و..
برای درک SRP و خیلی چیزهای دیگه میتونید پروژه های کد باز جناب نصیری SubtitleTools و Blogger auto poster رو ببینید

ادامه دارد …

نظرات

  1. امیر حسین جلوداری۹/۲۵/۱۳۹۰ ۱:۲۴ قبل‌ازظهر

    عالی بود ... امیدوارم همین جوری با قدرت به کارتون ادامه بدین

    پاسخحذف
  2. سلام.
    ممنون.
    من مطلب شما رو خواندم و این http://dimecasts.net/Casts/CastDetails/88 Cast رو هم دیدم که مربوط به همین SRP هست.
    نکته ای که برای من جای سوال دارد اینه که هر کلاس الآن فقط حاوی یک متد هست !
    ممنون میشم قدری توضیح بدید.

    پاسخحذف
  3. ممنون از سایتی که معرفی کردید.

    سوال خوبی بود (دقیقا منم اول همین فکر رو میکردم) امکانش هست که با رعایت این اصل
    کلاستون فقط یک متد داشته باشه ولی این یک قانون نیست برای رفع این ابهام مطالبی
    که در رابطه با SRP
    دیدم میگن از واژه JOB  بجای Responsibility  استفاده کنید چون در واقع تک مسئولیتی بودن یک
    کلاس منجر به اون ابهام میشه.

    نکته دیگه ی هم که هست رعایت این اصل منجر به خلوت شدن کلاس های شما میشه که در
    آینده نگهداری اونا رو راحتر میکنه

    برای مثال از تک متده بودن یک کلاس هم میتونم کلاس Logger  رو معرفی کنم  که معمولا تک متده هستن.

    برای مطالعه بیشتر هم این مطلب
    رو بخون که در همون ابتدا تاکید کرده SRP به این معنی
    نیست که کلاس شما بایستی تک متده باشه.

    پاسخحذف
  4. ممنون. مطلب خوبی رو دارید دنبال میکنید

    پاسخحذف
  5. مطالب خیلی خوبی دارین ارائه میدین. صنع نرم افزار در حال احتزار ما سالهاست از اصول اولیه مهندسی نرم افزار دور شده و به همین دلیل با انبوهی از نرم افزارهای فاقد کارایی مواجه هستیم.
    یک نکته اساسی در زمان تطراحی سیستم ها یا همین توضیح اصول اولیه مهندسی نرم افزار اینه که اصلا به بانک اطلاعاتی یا repository کاری نداریم. بنا براین اینکه قراره داده ها توی چه بانک اطلاعاتی ذخیره یا بازیابی بشن در زمان طراحی سیستم نباید در نظر گرفته بشه.

    پاسخحذف
  6. سلام
    جناب صاحب؛
    مطلب مفيديه ولي يه نكته شما فرموديد كه
     "این اصل میگه هر کلاس فقط باید یک مسئوليت داشته و همچنین میگه هر کلاس باید یک دلیل برای تغییر داشته باشه "
    قسمت اولش قبول، ولي قسمت دومش كه "هر کلاس باید یک دلیل برای تغییر داشته باشه " رو بر چه اساسي ميفرماييد؟
    من متن ويكيپديا رو هم كه نگاه كردم،  اين قسمت رو نديدم.

    پاسخحذف
  7. سلام معذرت، دليلش رو پيدا كردم
    سوال قبليم رو نديد بگيريد.
    ممنون.

    پاسخحذف

ارسال یک نظر

پست‌های معروف از این وبلاگ

مقدمه ای بر RavenDB – قسمت دوم

مقدمه ای بر RavenDB – قسمت سوم

lnav ابزاری بسیار کاربردی برای پیمایش لاگ ها در لینوکس و البته مک