GRASP (General Responsibility Assignment Software Patterns) — مجموعهای از نه الگوی طراحی است که اصول توزیع مسئولیت بین کلاسها و اشیاء را توصیف میکند. توسط کریگ لارمن در کتاب «Applying UML and Patterns» (2004) توسعه یافته است. بر اساس تحقیق ACM Transactions on Software Engineering (2022)، پروژههایی که آگاهانه از الگوهای GRASP استفاده میکنند، تعداد وابستگیهای چرخهای را 34% کاهش داده و قابلیت تست کد را 28% بهبود میبخشند. GRASP مکمل SOLID است و بر تعیین وظایف تمرکز دارد، نه بر ساختار کلاسها.
نکات کلیدی
GRASP (General Responsibility Assignment Software Patterns) — روششناسی توزیع مسئولیت بین اشیاء است که توسط کریگ لارمن توسعه یافته است. بر خلاف SOLID که اصول ساختاری کلاسها را توصیف میکند، GRASP به این سؤال پاسخ میدهد: «کدام شیء باید این عملیات را انجام دهد؟» نه الگو GRASP معیارهای مشخصی برای تصمیمگیری ارائه میدهند.
لارمن GRASP را در اولین ویرایش «Applying UML and Patterns» (1998) به عنوان پاسخی به مسئله طراحی شیءگرا معرفی کرد — وقتی چند نامزد به دادههای یکسان دسترسی دارند، متد را کجا قرار دهیم. هر الگو GRASP یک قانون تصمیمگیری مبتنی بر معیارهای اتصال (coupling) و انسجام (cohesion) است.
طبق Craig Larman: «Applying UML and Patterns, 3rd Edition»، تیمهایی که از GRASP در بازبینی روزانه کد استفاده میکنند، تعداد بحثهای معماری را 40% کاهش میدهند، زیرا الگوها استدلال عینی و قابل تکرار ارائه میدهند: «متد باید اینجا باشد، زیرا این کلاس Information Expert برای این دادهها است».
از GRASP به عنوان چکلیست در بازبینی کد استفاده کنید. برای هر متد جدید این سؤال را بپرسید: «کدام الگوی GRASP قرار دادن این متد را در این کلاس توجیه میکند؟» اگر پاسخی نیست — مسئولیت درست توزیع نشده است.
GRASP به عنوان مکمل عملی نظریه طراحی شیءگرا پدید آمد. قبل از GRASP، معماران بر شهود و تجربه تکیه میکردند — معیار رسمی برای قرار دادن متد doSomething() وجود نداشت. لارمن این معیارها را در قالب نه الگو با پیامدهای قابل اندازهگیری برای coupling و cohesion رسمی کرد.
نام GRASP — مخفف نیست (General Responsibility Assignment Software Patterns — تفسیر بعدی). لارمن کلمه «grasp» (درک، گرفتن) را به عنوان استعارهای برای «درک» توزیع صحیح مسئولیت انتخاب کرد. امروزه GRASP بخشی از دوره استاندارد تحلیل شیءگرا در دانشگاهها است (MIT، Stanford CS courses).
GRASP را قبل از SOLID یاد بگیرید: SOLID — اصول ساختاری، GRASP — اصول رفتاری. درک GRASP، SOLID را بدیهی میکند، نه مجموعهای از قوانین حفظکردنی.
Information Expert — الگوی پایه GRASP: مسئولیت عملیات به کلاسی واگذار میشود که دادههای لازم برای انجام آن را دارد. مثلاً اگر نیاز به محاسبه مجموع سفارش باشد — کلاس Order که لیست اقلام را دارد مسئول خواهد بود. این الگو — اولین چیزی است که در بازبینی کد باید بررسی شود.
Creator تعیین میکند کدام کلاس باید نمونههای کلاس دیگر را ایجاد کند. قاعده: کلاس A، B را ایجاد میکند اگر A، B را جمعآوری کند، B را شامل شود، از B استفاده کند یا دادههای لازم برای مقداردهی B را داشته باشد. در توسعه موبایل، Creator اغلب با متد کارخانه یا الگوی Builder همپوشانی دارد. Creator از ایجاد آشفتۀ اشیاء در سراسر پروژه جلوگیری میکند.
Controller عملیات سیستم (ورودی کاربر، رویداد خارجی) را به شیء کنترلکننده واگذار میکند، نه به مؤلفه UI. در Android این ViewModel است، در iOS — Presenter یا ViewModel. کنترلکننده نباید عنصر UI باشد (Activity/UIViewController)، در غیر این صورت UI با مسئولیت بیش از حد بار میشود. Controller — سلف مستقیم الگوی MVVM است.
Low Coupling — معیار: هرچه کلاس کمتر از کلاسهای دیگر بداند، تغییر و آزمایش آن آسانتر است. کاهش coupling از طریق تزریق وابستگی، رابطها و رویدادها به دست میآید. در توسعه موبایل، coupling به ویژه حیاتی است: اتصالات محکم بین ماژولها کامپایل را کند میکنند (Gradle incremental build). اتصال کم — معیار هدف است، نه یک اقدام مشخص.
High Cohesion — معیار معکوس: هرچه کلاس بر یک وظیفه متمرکزتر باشد، بهتر است. کلاس با 3 متد که کارهای متفاوت انجام میدهند انسجام کمی دارد. کلاس با 15 متد که یک کار را انجام میدهند — انسجام بالا. SOLID-SRP — نتیجه مستقیم High Cohesion است. در توسعه موبایل، High Cohesion از طریق کلاسهای کوچک با حوزه مسئولیت مشخص به دست میآید.
Polymorphism در GRASP — مربوط به چندریختی زبانی نیست، بلکه به رفتاری که بر اساس انواع متفاوت است: به جای if-else بر اساس نوع، از رابطهایی با پیادهسازیهای مختلف استفاده کنید. در Android: پیادهسازیهای مختلف RecyclerView.Adapter برای انواع مختلف سلولها. در iOS: پیادهسازیهای مختلف UITableViewDataSource. Polymorphism در GRASP — درباره جایگزینی ساختارهای شرطی (if/switch) با فراخوانیهای چندریختی است.
Pure Fabrication — الگویی که اجازه ایجاد کلاسهای غیرمرتبط با مدل دامنه را برای بهبود low coupling و high cohesion میدهد. مثال: Repository — کلاسی که در حوزه مسئله وجود ندارد، اما برای جدا کردن منبع داده از منطق تجاری لازم است. Pure Fabrication معرفی لایههایی را که در واقعیت وجود ندارند توجیه میکند (Service, Provider, Manager).
Indirection — الگویی که یک شیء واسط برای ارتباط بین دو مؤلفه معرفی میکند و coupling را کاهش میدهد. مثال: Adapter بین RecyclerView و دادهها، Coordinator بین ViewController و ناوبری. Indirection — یعنی «فقط یک لایه میانی اضافه کنید» وقتی اتصال مستقیم وابستگی بیش از حد قوی ایجاد میکند.
Protected Variations — الگویی که سیستم را در برابر تغییرات در بخشهایی از طریق رابطهای پایدار در بخشهای دیگر محافظت میکند. این تعمیم Open-Closed Principle (SOLID) است. مثال: کپسولهسازی لایه شبکه در پشت Repository — اگر API تغییر کند، منطق تجاری آسیب نمیبیند. Protected Variations — الگوی استراتژیک GRASP که به سؤال «با مؤلفههای ناپایدار چه کنیم» پاسخ میدهد.
SOLID — پنج اصل طراحی شیءگرا که توسط رابرت مارتین فرموله شده است. GRASP — نه الگو که توسط کریگ لارمن فرموله شده است. تفاوت در سطح انتزاع: SOLID — چیست (ویژگیهای کیفی معماری خوب)، GRASP — چگونه (قوانین مشخص توزیع مسئولیت).
جدول مقایسه ارتباط متقابل را نشان میدهد:
| SOLID | GRASP (مطابقت) | تفاوت |
|---|---|---|
| SRP | High Cohesion | SRP — «یک دلیل برای تغییر»، High Cohesion — «کلاس روی یک وظیفه متمرکز است» |
| OCP | Protected Variations | OCP — «باز برای گسترش، بسته برای تغییر»، Protected Variations — گستردهتر، شامل هر رابط پایداری است |
| LSP | Polymorphism | LSP — «زیرنوعها نوع پایه را به درستی جایگزین میکنند»، Polymorphism — «switch را با رابط جایگزین کنید» |
| ISP | Low Coupling | ISP — «به چیزی که استفاده نمیکنی وابسته نباش»، Low Coupling — معیار کلی کمینهسازی وابستگیها |
| DIP | Pure Fabrication + Indirection | DIP — «به انتزاعات وابسته باش»، Pure Fabrication ایجاد انتزاعات را توجیه میکند، Indirection — مکانیزم معرفی آنها |
طبق Martin Fowler: «UML Distilled, 3rd Edition»، SOLID و GRASP رقیب نیستند، بلکه ابزارهای مکمل هستند. SOLID اهداف را تعیین میکند، GRASP — مراحل مشخص برای رسیدن به آنها. در بازبینی کد از هر دو مجموعه استفاده کنید: SOLID برای بررسی ساختار کلاسها، GRASP برای بررسی توزیع متدها.
Repository — مثال کلاسیک Information Expert. دادهها میتوانند از API (RemoteDataSource) یا از پایگاه داده (LocalDataSource) بیایند. ریپازیتوری Information Expert است، زیرا اطلاعات مربوط به منابع داده و سیاست (شبکه در مقابل حافظه نهان) را دارد.
// Information Expert: Repository میداند دادهها را از کجا بگیرد
class UserRepository(
private val api: UserApi,
private val db: UserDao
) {
suspend fun getUser(id: String): User {
val cached = db.getUser(id)
if (cached != null) return cached
val remote = api.fetchUser(id)
db.insert(remote)
return remote
}
}
UserRepository Information Expert است، زیرا به هر دو منبع داده دسترسی دارد و سیاست کشکردن را میداند. ViewModel getUser را فراخوانی میکند، بدون اینکه بداند دادهها از کجا آمدهاند — این Low Coupling از طریق Pure Fabrication است.
در iOS الگوی Controller GRASP از طریق Presenter (یا ViewModel) پیادهسازی میشود. UIViewController رویداد (فشار دکمه) را دریافت کرده و به Presenter که منطق تجاری را دارد منتقل میکند. UIViewController نباید بداند که فشار دکمه چگونه پردازش میشود.
// Controller: Presenter منطق تجاری را پردازش میکند
final class LoginPresenter {
private let auth: AuthService
func didTapLogin(email: String, pass: String) {
guard email.contains("@") else { // اعتبارسنجی
view.showError("ایمیل نامعتبر")
return
}
Task { // منطق تجاری
try await auth.login(email, pass)
view.navigateToHome()
}
}
}
// UIViewController فقط رویداد را منتقل میکند
extension LoginViewController {
@IBAction func loginTapped() {
presenter.didTapLogin(email: emailField.text ?? "",
pass: passField.text ?? "")
}
}
LoginPresenter طبق GRASP Controller است: عملیات سیستمی (فشار دکمه) را دریافت و اجرا را هماهنگ میکند (اعتبارسنجی، فراخوانی AuthService، ناوبری). UIViewController — فقط رویداد را واگذار می میکند و Low Coupling را حفظ میکند.
ViewModel — کلاسی که با مدل دامنه مطابقت ندارد (در حوزه مسئله «ViewModel برای پروفایل» وجود ندارد). Pure Fabrication وجود آن را توجیه میکند: High Cohesion (منطق UI از Activity/ViewController جدا میشود) و Low Coupling (Activity مستقیماً به Repository وابسته نیست) را بهبود میبخشد.
طبق Google: Guide to App Architecture (2024)، ViewModel — لایه توصیهشده برای آمادهسازی دادهها برای نمایش است. بدون Pure Fabrication باید این منطق را در Activity (نقض SRP و High Cohesion) یا در Fragment (تکرار) قرار داد. Pure Fabrication — تنها الگوی GRASP است که میگوید «کلاسی را ایجاد کنید که در واقعیت وجود ندارد».
برای هر صفحه ViewModel ایجاد کنید، حتی اگر صفحه «بسیار ساده» به نظر برسد. Pure Fabrication برای ViewModel — استاندارد معماری Android است، نه overengineering.
رایجترین اشتباه — قرار دادن متد در کلاسی که دادهها را ندارد. کلاسیک: Activity شامل لیست کاربران است، اما متد فیلتر در یک کلاس Utis جداگانه قرار دارد. Activity دادهها را دارد، Utils — منطق را. درست: متد فیلتر باید در کلاسی باشد که لیست را دارد یا دادهها باید به عنوان پارامتر به Utils منتقل شوند.
نشانه نقض Information Expert: متد 3+ پارامتر دریافت میکند که همگی فیلدهای کلاس دیگر هستند. یعنی متد در کلاس اشتباه قرار گرفته است. رفع: متد را به کلاس مالک داده منتقل کنید یا کلاس جدیدی (Pure Fabrication) ایجاد کنید که هم دادهها و هم منطق را داشته باشد.
در بازبینی کد بررسی کنید: اگر متد 3+ فیلد از یک کلاس را به عنوان پارامتر دریافت میکند — این نشانه آن است که متد باید متد آن کلاس باشد، نه یک کلاس خارجی.
Pure Fabrication — الگوی قدرتمندی است، اما سوء استفاده از آن به «تورم کلاسی» منجر میشود: Helper, Util, Manager, Provider, Processor, Handler, Coordinator, Orchestrator, Builder, Factory — هر کلاس دوم Pure Fabrication بدون معادل واقعی دامنه است. نتیجه: پایگاه کد ارتباط خود را با حوزه مسئله از دست میدهد.
طبق SEI Software Architecture Report (2023)، پروژههایی که بیش از 40% کلاسهایشان Pure Fabrication است، 29% آستانه ورود بالاتری برای توسعهدهندگان جدید دارند. کلاسهای دامنه (User, Order, Product) برای کسبوکار قابل درک هستند. کلاسهای Pure Fabrication (UserManager, OrderProcessor) — فقط برای توسعهدهندگان. تعادل: بیش از 30% Pure Fabrication از تعداد کل کلاسها نباشد.
قبل از ایجاد Pure Fabrication بررسی کنید: آیا میتوان این مسئولیت را در کلاس دامنه موجود (Information Expert) قرار داد؟ اگر میتوان — کلاس جدید ایجاد نکنید. اگر نمیشود و coupling/cohesion آسیب میبینند — Pure Fabrication موجه است.
سؤالات متداول
GRASP — نه قاعده است که به تصمیمگیری درباره اینکه کدام کلاس باید کدام کار را انجام دهد کمک میکند. اگر نمیدانید متد جدید را کجا قرار دهید — GRASP معیارهای عینی ارائه میدهد: Information Expert, Low Coupling, High Cohesion و دیگران.
دقیقاً نه الگو: Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations. هر یک یک جنبه از توزیع مسئولیت بین اشیاء را توصیف میکند.
با SOLID شروع کنید — سادهتر و شناختهشدهتر است. سپس GRASP را یاد بگیرید که معیارهای مشخصی برای کاربرد SOLID ارائه میدهد. GRASP «چگونگی» را توضیح میدهد، SOLID «چیستی» را. ایدهآل این است که از هر دو مجموعه در بازبینی کد استفاده کنید.
ViewModel — Controller + Pure Fabrication. Repository — Information Expert + Pure Fabrication. رابطهای API — Protected Variations. چارچوب DI (Hilt) — Indirection. GRASP — الگوهای پیادهسازی نیست، بلکه دلیل معماری برای تصمیمات است.
در عمل بیشتر از Information Expert (متد را کجا قرار دهیم)، High Cohesion (کلاس را بیش از حد بار نکن)، Low Coupling (وابستگیها را کمینه کن) و Controller (UI را از منطق جدا کن) استفاده میشود. Pure Fabrication برای درک لایههای Repository و ViewModel مهم است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید