معماری‌های پیشرفته اندروید

آموزش جامع الگوهای معماری و طراحی نرم‌افزار برای اندروید

زمان مطالعه: ۲۵ دقیقه

معماری نرم‌افزار چیست؟

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

چرا معماری مهم است؟
  • قابلیت نگهداری: کد آسان‌تر قابل تغییر و بهبود است
  • قابلیت تست: هر بخش به طور مستقل قابل تست است
  • قابلیت توسعه: اضافه کردن ویژگی‌های جدید آسان‌تر است
  • قابلیت درک: کد برای سایر توسعه‌دهندگان قابل فهم‌تر است
  • عملکرد: معماری خوب عملکرد بهتری دارد

MVVM (Model-View-ViewModel)

معماری پیشنهادی گوگل

MVVM یکی از محبوب‌ترین الگوهای معماری در اندروید است که توسط گوگل توصیه می‌شود. این معماری جداسازی منطق کسب‌وکار از رابط کاربری را فراهم می‌کند.

Model

داده‌ها و منطق کسب‌وکار

  • Entity Classes
  • Repository
  • Data Sources
View

رابط کاربری

  • Activity/Fragment
  • Composable Functions
  • XML Layouts
ViewModel

لایه میانی

  • State Management
  • Business Logic
  • Data Processing
// Model data class User( val id: String, val name: String, val email: String ) // Repository class UserRepository @Inject constructor( private val apiService: ApiService, private val userDao: UserDao ) { suspend fun getUsers(): Flow> { return flow { // ابتدا از کش بخوان emit(userDao.getAllUsers()) // سپس از سرور دریافت کن val users = apiService.getUsers() userDao.insertUsers(users) emit(users) } } } // ViewModel @HiltViewModel class UserViewModel @Inject constructor( private val userRepository: UserRepository ) : ViewModel() { private val _users = MutableStateFlow>(emptyList()) val users: StateFlow> = _users.asStateFlow() private val _isLoading = MutableStateFlow(false) val isLoading: StateFlow = _isLoading.asStateFlow() fun loadUsers() { viewModelScope.launch { _isLoading.value = true try { userRepository.getUsers() .collect { users -> _users.value = users } } catch (e: Exception) { // مدیریت خطا } finally { _isLoading.value = false } } } } // View (Compose) @Composable fun UserScreen( viewModel: UserViewModel = hiltViewModel() ) { val users by viewModel.users.collectAsState() val isLoading by viewModel.isLoading.collectAsState() LaunchedEffect(Unit) { viewModel.loadUsers() } if (isLoading) { CircularProgressIndicator() } else { LazyColumn { items(users) { user -> UserItem(user = user) } } } }
MVVM ViewModel StateFlow Repository

Clean Architecture

معماری تمیز و مقیاس‌پذیر

Clean Architecture یک الگوی معماری است که توسط Robert C. Martin معرفی شده و هدف آن ایجاد نرم‌افزاری قابل تست، قابل نگهداری و مستقل از فریم‌ورک است.

لایه‌های Clean Architecture
Presentation Layer
UI, ViewModels, Activities
Domain Layer
Use Cases, Entities, Repository Interfaces
Data Layer
Repository Implementation, Data Sources, API
// Domain Layer - Entities data class User( val id: String, val name: String, val email: String ) // Domain Layer - Use Cases class GetUsersUseCase @Inject constructor( private val userRepository: UserRepository ) { suspend operator fun invoke(): Flow> { return userRepository.getUsers() } } // Domain Layer - Repository Interface interface UserRepository { suspend fun getUsers(): Flow> suspend fun getUserById(id: String): User? suspend fun saveUser(user: User) } // Data Layer - Repository Implementation class UserRepositoryImpl @Inject constructor( private val apiService: ApiService, private val userDao: UserDao ) : UserRepository { override suspend fun getUsers(): Flow> { return flow { // ابتدا از کش بخوان emit(userDao.getAllUsers()) // سپس از سرور دریافت کن try { val users = apiService.getUsers() userDao.insertUsers(users) emit(users) } catch (e: Exception) { // در صورت خطا، داده‌های کش را برگردان emit(userDao.getAllUsers()) } } } override suspend fun getUserById(id: String): User? { return userDao.getUserById(id) } override suspend fun saveUser(user: User) { userDao.insertUser(user) } } // Presentation Layer - ViewModel @HiltViewModel class UserViewModel @Inject constructor( private val getUsersUseCase: GetUsersUseCase ) : ViewModel() { private val _users = MutableStateFlow>(emptyList()) val users: StateFlow> = _users.asStateFlow() fun loadUsers() { viewModelScope.launch { getUsersUseCase() .collect { users -> _users.value = users } } } }
مزایای Clean Architecture
  • استقلال از فریم‌ورک: کد مستقل از Android است
  • قابلیت تست: هر لایه به طور مستقل قابل تست است
  • قابلیت نگهداری: تغییرات در یک لایه بر لایه‌های دیگر تأثیر نمی‌گذارد
  • قابلیت توسعه: اضافه کردن ویژگی‌های جدید آسان است
  • قابلیت درک: ساختار کد واضح و قابل فهم است
Clean Architecture Use Cases Entities Repository Pattern

مقایسه MVP و MVVM

MVP (Model-View-Presenter)

MVP الگوی قدیمی‌تری است که هنوز در برخی پروژه‌ها استفاده می‌شود، اما MVVM جایگزین بهتری است.

ویژگی MVP MVVM
ارتباط View و Presenter/ViewModel مستقیم (Interface) غیرمستقیم (Data Binding)
قابلیت تست خوب عالی
کد اضافی زیاد (Interface ها) کم
سازگاری با Compose مشکل عالی
توصیه گوگل خیر بله

Dependency Injection

مدیریت وابستگی‌ها

Dependency Injection الگویی است که به شما کمک می‌کند وابستگی‌های کلاس‌ها را مدیریت کنید و کد قابل تست‌تری بنویسید.

// بدون Dependency Injection class UserViewModel { private val userRepository = UserRepositoryImpl( ApiService(), UserDao() ) } // با Dependency Injection (Hilt) @HiltViewModel class UserViewModel @Inject constructor( private val userRepository: UserRepository ) : ViewModel() // تعریف Module @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides @Singleton fun provideApiService(): ApiService { return Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) } @Provides @Singleton fun provideUserDao(database: AppDatabase): UserDao { return database.userDao() } @Provides @Singleton fun provideUserRepository( apiService: ApiService, userDao: UserDao ): UserRepository { return UserRepositoryImpl(apiService, userDao) } }
Hilt Dependency Injection Singleton Module

بهترین شیوه‌ها

نکات مهم برای معماری خوب
  • جداسازی مسئولیت‌ها: هر کلاس یک وظیفه مشخص داشته باشد
  • وابستگی‌های معکوس: کلاس‌های سطح بالا به کلاس‌های سطح پایین وابسته نباشند
  • قابلیت تست: هر بخش به طور مستقل قابل تست باشد
  • کد تمیز: از نام‌گذاری مناسب و کد خوانا استفاده کنید
  • مستندات: معماری پروژه را مستند کنید
اشتباهات رایج
  • نوشتن همه چیز در Activity یا Fragment
  • عدم استفاده از Repository Pattern
  • نادیده گرفتن قابلیت تست
  • وابستگی مستقیم به فریم‌ورک‌ها
  • عدم استفاده از Dependency Injection

راهنمای مهاجرت

چگونه به معماری مدرن مهاجرت کنیم؟

  1. شروع تدریجی: ابتدا یک بخش کوچک را تغییر دهید
  2. Repository Pattern: دسترسی به داده‌ها را از طریق Repository انجام دهید
  3. ViewModel: منطق کسب‌وکار را به ViewModel منتقل کنید
  4. Dependency Injection: از Hilt برای مدیریت وابستگی‌ها استفاده کنید
  5. Testing: برای هر بخش تست بنویسید
  6. Clean Architecture: در پروژه‌های جدید از ابتدا استفاده کنید

مراحل بعدی

حالا که معماری‌های پیشرفته را یاد گرفتید، آماده یادگیری موضوعات پیشرفته هستید:

موضوعات پیشرفته شروع دوره‌ها