برنامه‌نویسی اندروید, کاتلین

کاربرد اصول SOLID در طراحی برنامه‌نویسی اندروید

اصول 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 در اندروید

  1.  مقیاس‌پذیری بالا
  2.  کاهش Bug
  3.  توسعه تیمی آسان‌تر
  4.  تست‌پذیری بهتر
  5.  قابلیت نگهداری بالا
  6.  Reusable بودن کدها

اشتباهات رایج

  1. ساخت Interface های غیرضروری
  2. یچیده کردن پروژه کوچک
  3. استفاده بیش‌ازحد از Abstraction

چه زمانی SOLID ضروری است؟

SOLID مخصوصاً در موارد زیر اهمیت دارد:

  • پروژه‌های بزرگ
  • اپلیکیشن‌های سازمانی
  • پروژه‌های تیمی
  • پروژه‌های بلندمدت
  • سیستم‌های چندماژوله

آیا همیشه باید SOLID را کامل اجرا کنیم؟

خیر.

در پروژه‌های کوچک گاهی اجرای کامل SOLID باعث پیچیدگی غیرضروری می‌شود.

باید تعادل رعایت شود.

ارتباط SOLID با Unit Testing

وقتی وابستگی‌ها از طریق Interface تزریق شوند:

  • Mock کردن راحت‌تر می‌شود
  • تست مستقل انجام می‌شود
  • وابستگی واقعی حذف می‌شود

جمع‌بندی

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

در این مقاله با:

  • Single Responsibility
  • Open/Closed
  • Liskov Substitution
  • Interface Segregation
  • Dependency Inversion

آشنا شدیم و کاربرد هرکدام را در برنامه‌نویسی اندروید بررسی کردیم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *