کاربرد اصول SOLID در طراحی برنامهنویسی اندروید
در توسعه اپلیکیشنهای اندرویدی، یکی از بزرگترین مشکلات پروژهها با افزایش حجم کدها شروع میشود. پروژهای که در ابتدا ساده و تمیز بوده، بهمرور تبدیل به مجموعهای از کلاسهای پیچیده، وابسته و سخت برای نگهداری میشود.
اینجاست که اصول SOLID اهمیت پیدا میکنند.
SOLID مجموعهای از ۵ اصل مهم در طراحی شیگرا است که باعث میشوند:
- کدها تمیزتر شوند
- پروژه مقیاسپذیرتر شود
- تستنویسی سادهتر شود
- توسعه تیمی راحتتر شود
- نگهداری پروژه آسانتر شود
- وابستگی بین بخشها کاهش یابد
این اصول توسط Robert C. Martin معرفی شدند و امروزه بخش مهمی از معماری نرمافزار مدرن محسوب میشوند.
SOLID چیست؟
کلمه SOLID از حروف اول ۵ اصل تشکیل شده است:
S → Single Responsibility Principle
O → Open/Closed Principle
L → Liskov Substitution Principle
I → Interface Segregation Principle
D → Dependency Inversion Principle
چرا SOLID در اندروید مهم است؟
در پروژههای اندرویدی معمولاً با موارد زیر روبهرو میشویم:
- Activity های بسیار بزرگ
- ViewModel های شلوغ
- Repository های پیچیده
- وابستگی شدید کلاسها
- سختی تست Unit Test
- تکرار کد
- مدیریت دشوار State
اصول SOLID کمک میکنند این مشکلات کنترل شوند.
اصل اول — Single Responsibility Principle (SRP)
اصل مسئولیت یکتا
این اصل میگوید:
هر کلاس فقط باید یک مسئولیت داشته باشد.
یعنی:
A class should have only one reason to change
مثال اشتباه در اندروید
فرض کنید یک Activity داریم که:
- API Call انجام میدهد
- دیتابیس ذخیره میکند
- UI را مدیریت میکند
- Validation انجام میدهد
class MainActivity : AppCompatActivity() {
fun login() {
// API Request
// Save Token
// Validate Email
// Update UI
}
}
این کلاس چند مسئولیت مختلف دارد.
پیادهسازی صحیح SRP
جدا کردن مسئولیتها
LoginValidator
LoginRepository
LoginViewModel
MainActivity
مثال حرفهای
Validator
class LoginValidator {
fun isValid(
email: String,
password: String
): Boolean {
return email.isNotEmpty() &&
password.length >= 6
}
}
Repository
class LoginRepository {
suspend fun login(
email: String,
password: String
) {
}
}
ViewModel
class LoginViewModel(
private val repository: LoginRepository
) : ViewModel() {
}
مزایای SRP در اندروید
- کاهش پیچیدگی کلاسها
- تستپذیری بهتر
- خوانایی بالاتر
- قابلیت توسعه راحتتر
- جلوگیری از God Class
اصل دوم — Open/Closed Principle (OCP)
اصل باز/بسته
کلاسها باید:
برای توسعه باز باشند
برای تغییر بسته باشند
یعنی بتوانیم بدون تغییر کد قبلی، قابلیت جدید اضافه کنیم.
مثال اشتباه
class PaymentManager {
fun pay(type: String) {
if(type == "CARD") {
} else if(type == "CRYPTO") {
}
}
}
هر بار روش پرداخت جدید اضافه شود باید کلاس را تغییر دهیم.
پیادهسازی صحیح OCP
استفاده از Interface
interface PaymentMethod {
fun pay()
}
Card Payment
class CardPayment : PaymentMethod {
override fun pay() {
}
}
Crypto Payment
class CryptoPayment : PaymentMethod {
override fun pay() {
}
}
Manager
class PaymentManager(
private val paymentMethod: PaymentMethod
) {
fun pay() {
paymentMethod.pay()
}
}
مزایای OCP در اندروید
- افزودن Feature جدید بدون تغییر کد قبلی
- کاهش Bug
- توسعه راحتتر
- مناسب معماری Clean Architecture
اصل سوم — Liskov Substitution Principle (LSP)
اصل جانشینی لیسکوف
این اصل میگوید:
کلاس فرزند باید بتواند جایگزین کلاس والد شود بدون اینکه رفتار سیستم خراب شود.
مثال اشتباه
open class Bird {
open fun fly() {
}
}
class Penguin : Bird() {
override fun fly() {
throw Exception()
}
}
پنگوئن پرواز نمیکند، بنابراین طراحی اشتباه است.
طراحی صحیح
interface Bird
Flying Bird
interface FlyingBird {
fun fly()
}
Eagle
class Eagle : Bird, FlyingBird {
override fun fly() {
}
}
Penguin
class Penguin : Bird
کاربرد LSP در اندروید
این اصل در موارد زیر اهمیت زیادی دارد:
- Base Repository
- Base ViewModel
- Adapter ها
- UseCase ها
- Service ها
اصل چهارم — Interface Segregation Principle (ISP)
اصل جداسازی Interface
این اصل میگوید:
کلاسها نباید مجبور شوند متدهایی را پیادهسازی کنند که استفاده نمیکنند.
مثال اشتباه
interface MediaPlayer {
fun playAudio()
fun playVideo()
fun recordVideo()
}
ممکن است بعضی کلاسها فقط Audio Player باشند.
طراحی صحیح
Audio Player
interface AudioPlayer {
fun playAudio()
}
Video Player
interface VideoPlayer {
fun playVideo()
}
Recorder
interface VideoRecorder {
fun recordVideo()
}
مزایای ISP
- کاهش وابستگی
- خوانایی بهتر
- Interface های کوچکتر
- تست آسانتر
اصل پنجم — Dependency Inversion Principle (DIP)
اصل وارونگی وابستگی
این اصل یکی از مهمترین اصول SOLID است.
میگوید:
کلاسهای سطح بالا نباید به کلاسهای سطح پایین وابسته باشند
هر دو باید به Abstraction وابسته باشند
مثال اشتباه
class UserRepository {
}
class UserViewModel {
private val repository =
UserRepository()
}
ViewModel مستقیم به Repository وابسته است.
طراحی صحیح با Interface
Repository Interface
interface UserRepository {
suspend fun getUsers(): List<String>
}
Repository Implementation
class UserRepositoryImpl :
UserRepository {
override suspend fun getUsers():
List<String> {
return emptyList()
}
}
ViewModel
class UserViewModel(
private val repository:
UserRepository
) : ViewModel()
Dependency Injection در اندروید
اصل DIP معمولاً همراه Dependency Injection استفاده میشود.
کتابخانههای معروف:
- Hilt
- Dagger
- Koin
مثال Hilt
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
fun provideRepository():
UserRepository {
return UserRepositoryImpl()
}
}
استفاده از SOLID در معماری MVVM
ترکیب:
MVVM + SOLID
یکی از استانداردترین روشهای برنامه نویسی اندروید است.
نمونه ساختار پروژه حرفهای
data/
domain/
presentation/
di/
repository/
network/
usecase/
SOLID در Jetpack Compose
در پروژههای مبتنی بر Jetpack Compose نیز SOLID اهمیت بالایی دارد.
مثال:
- Composable های کوچک
- State Hoisting
- جداسازی UI Logic
- Reusable Components
مثال State Hoisting
@Composable
fun LoginScreen(
email: String,
onEmailChange: (String) -> Unit
)
این روش با SRP و ISP هماهنگ است.
ارتباط SOLID با Clean Architecture
اصول SOLID پایه اصلی:
Clean Architecture
هستند.
در Clean Architecture:
- وابستگیها کنترل میشوند
- Interface ها اهمیت دارند
- Business Logic مستقل میشود
مزایای استفاده از SOLID در اندروید
- مقیاسپذیری بالا
- کاهش Bug
- توسعه تیمی آسانتر
- تستپذیری بهتر
- قابلیت نگهداری بالا
- Reusable بودن کدها
اشتباهات رایج
- ساخت Interface های غیرضروری
- یچیده کردن پروژه کوچک
- استفاده بیشازحد از Abstraction
چه زمانی SOLID ضروری است؟
SOLID مخصوصاً در موارد زیر اهمیت دارد:
- پروژههای بزرگ
- اپلیکیشنهای سازمانی
- پروژههای تیمی
- پروژههای بلندمدت
- سیستمهای چندماژوله
آیا همیشه باید SOLID را کامل اجرا کنیم؟
خیر.
در پروژههای کوچک گاهی اجرای کامل SOLID باعث پیچیدگی غیرضروری میشود.
باید تعادل رعایت شود.
ارتباط SOLID با Unit Testing
وقتی وابستگیها از طریق Interface تزریق شوند:
- Mock کردن راحتتر میشود
- تست مستقل انجام میشود
- وابستگی واقعی حذف میشود
جمعبندی
اصول SOLID یکی از مهمترین پایههای طراحی نرمافزار حرفهای هستند و در توسعه اپلیکیشنهای اندرویدی نقش بسیار مهمی دارند.
در این مقاله با:
- Single Responsibility
- Open/Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
آشنا شدیم و کاربرد هرکدام را در برنامهنویسی اندروید بررسی کردیم.