به گفته عمو باب، اصل مسئولیت واحد (SRP) تنها زمانی میتواند به درستی اعمال شود که شما به وضوح بازیگران سیستم را شناسایی کنید.
"یک ماژول باید در برابر یک و فقط یک بازیگر مسئول باشد."
گاهی اوقات، بهترین راه برای اثبات یک اصل، بررسی این است که وقتی آن نقض میشود چه اتفاقی میافتد.
بیایید به یک مثال رایج نگاه کنیم:
متد calculatePay() توسط بخش حسابداری تعریف و استفاده میشود که به مدیر ارشد مالی گزارش میدهد.
متد reportHours() توسط بخش منابع انسانی استفاده میشود و به مدیر ارشد عملیات گزارش میدهد.
متد save() توسط مدیران پایگاه داده، تحت نظر مدیر ارشد فناوری مدیریت میشود.

در نگاه اول، ممکن است به نظر برسد که این کلاس از SRP پیروی میکند. به هر حال، هر متد یک کار واحد دارد. اما در واقعیت، این نقض آشکار SRP است. چرا؟
زیرا قرار دادن این سه متد در یک کلاس واحد، سه بازیگر مختلف را به هم متصل میکند - به این معنی که تغییرات یک تیم ممکن است ناخواسته بر سایر تیمها تأثیر بگذارد.
تصور کنید که هر دو تابع calculatePay() و reportHours() یک متد کمکی به نام regularHours() را به اشتراک بگذارند.
این متد ممکن است مانند یک تابع مسئولیت واحد به نظر برسد. اما اگر بخش حسابداری بخواهد نحوه محاسبه اضافه کاری را تغییر دهد، چه اتفاقی میافتد؟ آنها regularHours() را برای رفع نیازهای خود تغییر میدهند.
اما مشکل اینجاست: منابع انسانی نیز از regularHours() استفاده میکند - و از این تغییر آگاه نیستند. تیم حسابداری آزمایشهای خود را انجام میدهد و همه چیز خوب به نظر میرسد. اما چند هفته بعد، منابع انسانی شروع به شکایت از گزارشهای نادرست میکند.
زمانی که مشکل کشف میشود، سازمان ممکن است از دادههای نادرست و تصمیمات نادرست رنج برده باشد.
SRP به ما میگوید که با تفکیک مسئولیتها بر اساس عامل، میتوان از این مشکل جلوگیری کرد.
حالا تصور کنید دو توسعهدهنده روی این کلاس کار میکنند:
یکی calculatePay() را برای تیم مالی بهروزرسانی میکند.
دیگری reportHours() را برای منابع انسانی بهروزرسانی میکند.
وقتی زمان ادغام فرا میرسد، آنها با تداخل مواجه میشوند - با وجود اینکه ابزارهای کنترل نسخه مدرن کاملاً پیشرفته هستند، تداخلهای ادغام در کلاسهای مشترک هنوز خطرناک هستند و میتوانند اشکالات ظریفی ایجاد کنند.
یک راه حل عملی، جداسازی دادهها از رفتار است. به جای یک کلاس بزرگ Employee، مسئولیتها را تقسیم میکنید:
PayCalculator منطق حقوق و دستمزد را مدیریت میکند.
HoursReporter ساعات کاری را مدیریت میکند.
EmployeeRepository با پایداری سروکار دارد.
همه این کلاسها میتوانند به یک ساختار EmployeeData مشترک دسترسی داشته باشند - یک نگهدارنده داده ساده بدون هیچ منطق تجاری.
هر کلاس فقط شامل کد منبع لازم برای مسئولیت خود است. آنها از یکدیگر آگاه نیستند و احتمال همپوشانی تصادفی یا اتصال ناخواسته را کاهش میدهند.
برای مشاهده تصویر در اندازه کامل، اینتر را فشار دهید یا کلیک کنید
ممکن است اعتراض کنید: "حالا من سه کلاس برای نمونهسازی و ردیابی دارم!"
منصفانه است. یک رویکرد رایج در اینجا استفاده از الگوی نما است - یک کلاس واحد که پیچیدگی زیرسیستم را پنهان میکند و یک رابط کاربری سادهشده به دنیای خارج ارائه میدهد.
برای مشاهده تصویر در اندازه کامل، اینتر را فشار دهید یا کلیک کنید
بنابراین برنامه شما با یک کلاس سروکار دارد، اما در زیر کاپوت، مسئولیتها از هم جدا میمانند.
اصل مسئولیت واحد باید نه تنها در سطح متد، بلکه در کل معماری - از بالا به پایین - اجرا شود.
هر بازیگر در سیستم باید یک کلاس مربوطه داشته باشد، با متدهای متمرکز که فقط نیازهای آن بازیگر را برآورده میکنند. این منجر به سیستمی میشود که مقیاسپذیری، آزمایش و نگهداری آن آسانتر است.