SRP: چیست، اصل مسئولیت واحد در توسعه

نویسنده: IT Sectr منتشر شده: 2026-05-11 زمان مطالعه: 9 دقیقه

SRP (Single Responsibility Principle) — اولین اصل SOLID که تعیین می‌کند: هر کلاس یا ماژول باید دقیقاً یک دلیل برای تغییر داشته باشد. این اصل توسط رابرت مارتین در کتاب Clean Architecture (2017) فرموله شد و به پایه طراحی ماژولار تبدیل شد. طبق این کتاب، اعمال SRP مستقیماً وابستگی بین مؤلفه‌ها را کاهش می‌دهد و تغییرات آبشاری را هنگام بهبود عملکرد حذف می‌کند.

نکات اصلی

  • SRP — اولین اصل SOLID، نیازمند یک مسئولیت برای هر کلاس
  • دلیل تغییر — تنها معیار جداسازی مسئولیت در ماژول
  • نقض SRP به کد وابسته‌ای منجر می‌شود که تست و گسترش آن دشوار است
  • اعمال اصل بازسازی کد را ساده می‌کند و ریسک خطاهای بازگشتی را کاهش می‌دهد
  • SRP در توسعه موبایل به جداسازی منطق UI، قوانین تجاری و کار با داده کمک می‌کند

SRP (Single Responsibility Principle) چیست؟

SRP (Single Responsibility Principle) — اصل مسئولیت واحد که می‌گوید: هر کلاس یا ماژول باید دقیقاً یک دلیل برای تغییر داشته باشد. این به این معنی نیست که کلاس باید دقیقاً یک عملیات انجام دهد. صحبت درباره گروهی از اقدامات مرتبط است که با یک مسئولیت در برابر یک بازیگر متحد شده‌اند.

رابرت مارتین SRP را بر حسب بازیگران بازفرموله کرد: کلاس باید فقط به درخواست یک شخص ذی‌نفع یا یک گروه از افراد تغییر کند. اگر دو بازیگر مختلف تغییر یک کلاس را درخواست کنند — مسئولیت به درستی تقسیم نشده است.

برای مثال، کلاس Employee که هم حقوق را محاسبه می‌کند (درخواست حسابداری) و هم گزارش تهیه می‌کند (درخواست مدیریت)، SRP را نقض می‌کند. تغییر قوانین محاسبه ممکن است بر تهیه گزارش تأثیر بگذارد و بالعکس.

تعریف رسمی SRP

ماژول باید یک و تنها یک دلیل برای تغییر داشته باشد. دلیل تغییر توسط بازیگر — شخص یا سیستمی که نیازمندی را مطرح می‌کند — تعیین می‌شود. اگر نیازمندی‌های بازیگران مختلف منجر به تغییر یک ماژول شود — ماژول SRP را نقض می‌کند.

مفهوم بازیگر SRP را به ابزاری عملی برای تحلیل معماری تبدیل می‌کند، نه یک توصیه انتزاعی. هنگام طراحی سیستم کافی است بپرسیم: «چه کسی تغییر این کد را درخواست خواهد کرد؟» — اگر پاسخ شامل بیش از یک شخص ذی‌نفع باشد، مسئولیت باید تقسیم شود.

اصل مسئولیت واحد چگونه کار می‌کند

مسئولیت واحد از طریق گروه‌بندی متدهایی که به یک دلیل تغییر می‌کنند تحقق می‌یابد. کلاس به «نقطه جمع» منطق مرتبط تبدیل می‌شود، نه «چاقوی سوئیسی» برای همه موارد. این کار درک کد را ساده می‌کند: توسعه‌دهنده کلاس را می‌بیند و بلافاصله هدف آن را می‌فهمد.

مکانیزم کار SRP بر اساس قانون یک محور تغییر است. اگر عملکرد می‌تواند به دلایل مستقل تغییر کند — باید به کلاس‌های جداگانه منتقل شود. ارتباط بین این کلاس‌ها از طریق ترکیب یا تفویض اختیار ساخته می‌شود.

نقض SRP در «کلاس‌های خدا» (God Objects) ظاهر می‌شود که ده‌ها متد کار با داده‌های مختلف را شامل می‌شوند. تست چنین کلاسی دشوار است — تست یک متد نیاز به تنظیم محیط برای بقیه دارد. تغییر یک مسئولیت ممکن است دیگری را خراب کند که کد را شکننده می‌سازد.

در عمل، SRP به توسعه‌دهندگان کمک می‌کند به سؤال «این کد کجاست؟» پاسخ دهند. اگر هر مسئولیت در کلاس خود جدا شده باشد، یافتن فایل مورد نظر ثانیه‌ها طول می‌کشد. در پروژه Android با معماری MVVM این به این معنی است که UserViewModel فقط مسئول وضعیت صفحه کاربر است و UserRepository مسئول دریافت داده‌ها. توسعه‌دهنده‌ای که به دنبال منطق کش می‌گردد به UserCacheRepository می‌رود، نه ViewModel. چنین سازماندهی کد ورود اعضای جدید تیم را سرعت می‌بخشد و تعداد خطاها را هنگام بازسازی کد کاهش می‌دهد.

چرا SRP در توسعه موبایل مهم است

توسعه موبایل الزامات خاصی برای ماژولار بودن کد دارد. Android Fragment یا iOS ViewController اغلب به «نقاط جذب» منطق تبدیل می‌شوند: پردازش کلیک‌ها، فراخوانی API، تجزیه پاسخ، به‌روزرسانی UI — همه در یک کلاس. SRP نیاز به جداسازی این وظایف دارد.

در معماری Android SRP در توصیه‌های Google برای Jetpack گنجانده شده است: ViewModel مسئول وضعیت صفحه، Repository مسئول داده‌ها، UseCase مسئول منطق تجاری. هر مؤلفه یک دلیل برای تغییر دارد. در توسعه iOS الگوی MVVM و Coordinator از همان منطق پیروی می‌کنند.

پایبندی به SRP در پروژه‌های موبایل مزایای قابل اندازه‌گیری دارد: کاهش اندازه کلاس‌ها به میزان 40-60٪، کاهش زمان بازبینی کد و کاهش تعداد باگ‌های بازگشتی هنگام افزودن عملکرد جدید. ماژول‌های ایزوله پوشش با تست‌های واحد را آسان‌تر کرده و در سایر صفحه‌ها قابل استفاده مجدد هستند.

تأثیر SRP بر تست‌نویسی

تست‌های واحد کلاس‌های پایبند به SRP به اشیاء mock و تنظیمات کمتری نیاز دارند. اگر کلاس یک مسئولیت داشته باشد، وابستگی‌های آن محدود است. تست یک رفتار را بررسی می‌کند، نه ترکیبی از چند سناریوی نامرتبط.

طبق گزارش Google Testing Blog (2023)، کلاس‌های با مسئولیت واحد 35٪ پوشش بیشتری با تست‌ها در مقایسه با کلاس‌های تجمیعی نشان می‌دهند. توسعه‌دهندگان با اشتیاق بیشتری برای ماژول‌های کوچک و قابل فهم تست می‌نویسند.

مثال‌های SRP در Android و iOS

یک کلاس Android معمولی که SRP را نقض می‌کند — هم داده بار می‌کند، هم پاسخ را تجزیه می‌کند، هم UI را به‌روز می‌کند. پس از بازسازی، هر مسئولیت به یک مؤلفه جداگانه منتقل شده است.

kotlin
// نقض SRP: یک کلاس همه کار را انجام می‌دهد
class BadUserProfileActivity {
    fun loadUser(userId: Int) {
        // درخواست HTTP
        // تجزیه JSON
        // به‌روزرسانی UI
        // ذخیره در پایگاه داده
    }
}

// پس از اعمال SRP
class UserRepository {
    fun getUser(userId: Int): User
}

class UserViewModel {
    private val repo: UserRepository
    fun loadUser(userId: Int) { }
}

class UserProfileFragment {
    fun render(user: User) { }
}

مثال مشابه در iOS Swift با جداسازی لایه شبکه و لایه نمایش:

swift
// نقض SRP: ViewController داده و UI را مدیریت می‌کند
class BadProfileViewController: UIViewController {
    func viewDidLoad() {
        // درخواست URLSession
        // دیکد JSON
        // به‌روزرسانی label
    }
}

// پس از اعمال SRP
protocol UserServiceProtocol {
    func fetchUser(id: Int) async throws -> User
}

class ProfileViewModel {
    private let service: UserServiceProtocol
    func loadProfile(id: Int) { }
}

class ProfileViewController: UIViewController {
    func display(user: User) { }
}

بازسازی SRP معماری را پیچیده نمی‌کند — مسئولیت را توزیع مجدد می‌کند. مقدار کد ممکن است حتی با حذف تکرار کاهش یابد. هر کلاس جدید هدف مشخصی دارد و می‌تواند مستقل توسعه یابد.

ترکیب به عنوان جایگزین وراثت

ترکیب جایی که وراثت وابستگی‌های غیرضروری ایجاد می‌کند به پایبندی به SRP کمک می‌کند. به جای سوپرکلاس با ده‌ها متد، زیرکلاس مجموعه‌ای از اشیاء تخصصی را از طریق سازنده دریافت می‌کند. هر شیء مسئول عملکرد خود است.

در توسعه Android، الگوی Decorator امکان افزودن مسئولیت‌ها را بدون تغییر کلاس اصلی فراهم می‌کند. در iOS، زنجیره Middleware در لایه شبکه، ثبت وقایع، کش و احراز هویت را به ماژول‌های جداگانه تقسیم می‌کند.

نقض‌های معمول SRP و پیامدهای آنها

متداول‌ترین نقض — «God Class»: کلاسی که پایگاه داده را مدیریت می‌کند، اعلان‌ها ارسال می‌کند، گزارش تهیه می‌کند و ورودی کاربر را پردازش می‌کند. چنین کلاسی به گلوگاه پروژه تبدیل می‌شود: هر تغییری نیاز به تست بازگشتی کامل دارد.

در توسعه موبایل، نقض SRP ناشی از مخلوط کردن منطق تجاری و منطق UI در Activity، Fragment یا ViewController است. وقتی متد onClickListener همزمان داده را اعتبارسنجی می‌کند، API را فراخوانی می‌کند و visibility دکمه‌ها را به‌روز می‌کند — این نقض مستقیم اصل مسئولیت واحد است.

پیامدهای نقض SRP شامل: دشواری توسعه موازی (تداخل در یک فایل)، مشکل در تست واحد، هزینه بالای اعمال تغییرات و کاهش خوانایی کد. پروژه‌های با نقض سیستماتیک SRP 2-3 برابر زمان بیشتری برای افزودن عملکرد جدید نیاز دارند.

نشانگرهای نقض SRP در کد

می‌توان نقض SRP را با نشانه‌های غیرمستقیم تعیین کرد: کلاس بیش از ۲۰۰ خط دارد، ماژول‌هایی از لایه‌های مختلف برنامه وارد می‌کند (UI + network + database)، بیش از ۵ متد عمومی با موضوعات مختلف دارد. معیار انسجام (cohesion) — شاخص آماری: انسجام پایین متدها در داخل کلاس نشان‌دهنده نقض SRP است.

برای تشخیص نقض‌های SRP مفید است از ابزارهای تحلیل ایستا استفاده کنید: برای Android — Detekt با قانون TooManyFunctions، برای iOS — SwiftLint با قانون file_length. این ابزارها کلاس‌هایی که از آستانه‌های اندازه و پیچیدگی فراتر می‌روند را برجسته می‌کنند.

بازسازی کلاس‌های نقض‌کننده SRP از طریق Extract Class یا Extract Delegate انجام می‌شود: گروهی از متدهای مرتبط به یک کلاس جداگانه منتقل می‌شود و کلاس اصلی فراخوانی را به آنها تفویض می‌کند. اعمال تدریجی چنین بازسازی‌هایی «God Class» را به مجموعه‌ای از ماژول‌های با اتصال سست تبدیل می‌کند که هر کدام یک مسئولیت دارند. چنین رویکردی امکان بهبود معماری بدون توقف توسعه را فراهم می‌کند — بازسازی به صورت تکراری، یک ماژول در هر بار انجام می‌شود.

سوالات متداول

آیا SRP به این معنی است که کلاس باید یک متد داشته باشد؟

خیر. SRP درباره تعداد متدها نیست، بلکه درباره تعداد دلایل تغییر است. یک کلاس می‌تواند ده متد داشته باشد اگر همه آنها یک مسئولیت در برابر یک بازیگر را خدمت کنند. یک متد — افراط دیگری است که به تقسیم‌بندی بیش از حد کد منجر می‌شود.

تفاوت SRP با اصل وظیفه واحد چیست؟

این یک اصل است. Single Responsibility Principle هم به عنوان «مسئولیت واحد» و هم به عنوان «وظیفه واحد» ترجمه می‌شود. اصطلاح «مسئولیت» جوهر را دقیق‌تر منعکس می‌کند: صحبت درباره مسئولیت در برابر بازیگر است، نه درباره عملکرد فنی.

SRP چگونه با الگوی Repository مرتبط است؟

Repository — نتیجه مستقیم اعمال SRP به لایه داده است. به جای پخش منطق دسترسی به داده در ViewModel یا UseCase، Repository یک مسئولیت واحد را بر عهده می‌گیرد: ارائه داده با انتزاع منبع. این یک پیاده‌سازی کلاسیک SRP در معماری موبایل است.

آیا کلاس با SRP می‌تواند به کلاس‌های دیگر وابستگی داشته باشد؟

بله، SRP وابستگی‌ها را ممنوع نمی‌کند. کلاس با یک مسئولیت می‌تواند بخشی از کار را از طریق ترکیب به کلاس‌های دیگر تفویض کند. مهم است که این وظایف تفویض‌شده بخشی از همان مسئولیت باشند، نه یک دلیل مستقل برای تغییر.

چگونه بررسی کنیم که آیا کلاس SRP را رعایت می‌کند؟

سؤال بپرسید: «چه بازیگرانی ممکن است تغییر این کلاس را درخواست کنند؟» اگر پاسخ شامل بیش از یک بازیگر باشد — SRP نقض شده است. به علاوه: سعی کنید هدف کلاس را در یک جمله بدون حرف ربط «و» توصیف کنید. اگر موفق نشدید — کلاس کار زیادی انجام می‌دهد.

خلاصه

  • SRP (Single Responsibility Principle) — اولین اصل SOLID، نیازمند یک دلیل برای تغییر کلاس
  • دلیل تغییر توسط بازیگر — شخص یا سیستمی که نیازمندی به ماژول را مطرح می‌کند — تعیین می‌شود
  • نقض SRP به God Class، قابلیت تست پایین و هزینه بالای تغییرات منجر می‌شود
  • در توسعه موبایل SRP منطق UI، منطق تجاری و کار با داده را به مؤلفه‌های جداگانه تقسیم می‌کند
  • ترکیب با تفویض به اشیاء تخصصی بهتر از وراثت به رعایت SRP کمک می‌کند
  • ابزارهای تحلیل ایستا (Detekt, SwiftLint) به طور خودکار نقض‌های بالقوه SRP را تشخیص می‌دهند
  • تست‌های واحد کلاس‌های با SRP به اشیاء mock کمتری نیاز دارند و پوشش کد بالاتری نشان می‌دهند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید