SOLID: elvek, 5 OOP szabály és alkalmazás a fejlesztésben

Szerző: IT Sectr Megjelenés: 2026-05-11 Olvasási idő: 10 perc

SOLID — öt objektumorientált programozási alapelv, amelyet Robert C. Martin (Uncle Bob) fogalmazott meg a 2000-es évek elején. A DigitalOcean, 2024 szerint a SOLID a Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation és Dependency Inversion rövidítése. Ezek az elvek képezik a Clean Architecture alapját és az Android (MVP, MVVM, Clean Architecture) és iOS (VIPER, TCA) fejlesztésben használják őket.

Főbb pontok

  • SOLID — öt OOP-elv (SRP, OCP, LSP, ISP, DIP) betűszava, amelyet Robert C. Martin fogalmazott meg rugalmas és karbantartható kód létrehozásához.
  • SRP (Single Responsibility) — minden osztálynak egy oka van a változásra, egy felelősség modulonként.
  • OCP (Open-Closed) — az osztályok nyitottak a bővítésre, de zártak a módosításra, örökléssel és polimorfizmussal megvalósítva.
  • LSP (Liskov Substitution) — az alosztályok objektumainak ki kell tudniuk cserélni az alaposztály objektumait a program helyességének megváltoztatása nélkül.
  • ISP (Interface Segregation) — az ügyfelek nem függhetnek olyan interfészektől, amelyeket nem használnak, az interfészek legyenek szűkek és specifikusak.
  • DIP (Dependency Inversion) — a magas szintű modulok nem függnek az alacsony szintű moduloktól, mindkettő absztrakcióktól függ.

Mi az a SOLID? Az öt elv áttekintése

SOLID — egy mnemonikus betűszó, amely öt objektumorientált tervezési alapelvet jelöl. A kifejezést Robert C. Martin vezette be a „Design Principles and Design Patterns” (2000) című cikkében, majd később a „Agile Software Development: Principles, Patterns, and Practices” (2002) című könyvében népszerűsítette. A SOLID nem framework vagy könyvtár — ez egy gyakorlatgyűjtemény, amely a kódot kevésbé összekapcsoltabbá, jobban tesztelhetővé és könnyebben módosíthatóvé teszi.

A Clean Coder Blog, 2014 szerint minden SOLID-elv egy adott tervezési problémát old meg: az SRP a God-osztályokkal küzd, az OCP — a láncolatos változtatásokkal, az LSP — a helytelen örökléssel, az ISP — a kövér interfészekkel, a DIP — a szoros csatolással. Együtt alkotják a Clean Architecture alapját, amelyet MVP, MVVM és MVI mintájú Android projektekben használnak.

SRP: Single Responsibility Principle

Single Responsibility Principle (SRP) — az egyetlen felelősség elve. Megfogalmazás: „Egy osztálynak csak egy oka lehet a változásra.” Ez azt jelenti, hogy minden modul vagy osztály pontosan egy funkcióért vagy egy doménentitásért felelős. Ha egy osztály mind a felhasználókat, mind az e-mail küldést kezeli — két oka van a változásra, ami sérti az SRP-t.

A Robert C. Martin, 2002 szerint az SRP a legfontosabb és egyben a leggyakrabban megsértett elv. Mobilfejlesztésben az SRP-t gyakran az Activity/Fragment sérti, amely ötvözi az UI-logikát, navigációt, hálózati munkát és üzleti logikát. Megoldás — minden réteget külön osztályba helyezni: ViewModel az UI-logikához, Repository az adatokhoz, NavController a navigációhoz.

SRP példa: UserManager felosztása

Tekintsük a UserManager osztályt, amely betölti a profil, menti a beállításokat és e-maileket küld. Ez három különböző felelősség, mindegyiket külön osztályba kell különíteni: UserProfileRepository (betöltés), UserSettingsStorage (mentés) és EmailService (küldés). Az ügyfélkód (ViewModel) mindhármat Dependency Injection segítségével használja, és minden osztály könnyen tesztelhető elkülönítve és módosítható mások befolyásolása nélkül.

kotlin
// ❌ SRP megsértése: Activity tud a hálózatról, DB-ről és UI-ról
class ProfileActivity : AppCompatActivity() {
    fun loadProfile() {
        api.getUser() // Hálózati hívás
        db.saveUser()    // Munka DB-vel
        updateUI()         // UI frissítés
    }
}

// ✅ SRP betartva: rétegek szétválasztva
class ProfileViewModel : ViewModel() {
    private val repo = UserRepository()
    fun loadProfile() { repo.getUser() }
}

Az SRP megsértésének jelei: az osztály több mint 200 sort tartalmaz, módszerei vannak különböző területekről, gyakran változik különböző okokból. Android fejlesztésben a szabály egyszerű: az Activity csak a képernyř életciklusáért felelős, a ViewModel — az UI állapotáért, a Repository — az adatforrásokért.

SRP és mikroszolgáltatási architektúra

Az SRP elv nemcsak osztályokra, hanem szolgáltatásszintű architektúrára is vonatkozik. Minden mikroszolgáltatás egy doménentitásért felelős: UserService — csak felhasználók, PaymentService — csak fizetések, NotificationService — csak értesítések. Ez lehetővé teszi a szolgáltatások független skálázását, telepítését és tesztelését. Mobilalkalmazásban az SRP mikroszolgáltatási szinten az API-ügyfelek doménenkénti felosztásában nyilvánul meg.

OCP: Open-Closed Principle

Open-Closed Principle (OCP) — a nyitottság/zártság elve. Az osztályok legyenek nyitottak a bővítésre (új viselkedés adható hozzá) és zártak a módosításra (a meglévő kód nem változik). Polimorfizmus, absztrakt osztályok és interfészek segítségével érhető el. Ahelyett, hogy if-else-t adna egy meglévő metódushoz, új interfészimplementációt kell létrehozni.

A Clean Coder Blog, 2014 szerint az OCP a Strategy mintával kombinálva a leghatékonyabb. Például, ha egy alkalmazás különböző fizetési módokat támogat (Google Pay, Apple Pay, PayPal), nem kell switch-case-t hozzáadni a fizetési feldolgozóhoz. Minden fizetési mód implementálja a közös PaymentGateway interfészt, és egy új fizetési rendszer új osztályként adható hozzá a meglévő kód módosítása nélkül.

kotlin
// ✅ OCP: nyitott bővítésre, zárt módosításra
interface PaymentGateway {
    fun processPayment(amount: Double): Boolean
}

class GooglePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

// Új fizetési rendszer — a meglévő kód módosítása nélkül
class ApplePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

LSP: Liskov Substitution Principle

Liskov Substitution Principle (LSP) — Barbara Liskov helyettesítési elve. Ha S a T altípusa, akkor T objektumai helyettesíthetők S objektumaival a program tulajdonságainak megváltoztatása nélkül. Formálisan: az alaposztályt használó függvénynek helyesen kell működnie bármely alosztályával. Ha az alosztály kivételt dob ott, ahol az alaposztály nem — az LSP sérül.

A Robert C. Martin, 2002 szerint az LSP a legnehezebben érthető SOLID-elv. A megsértés klasszikus példája — a Square (négyzet) osztály, amely a Rectangle (téglalap) osztályból öröklődik. Ha a setWidth a Square számára beállítja mind a szélességet, mind a magasságot, az ügyfélkód, amely a Rectangle viselkedését várja, váratlan eredményt kap. Mobilfejlesztésben az LSP gyakran sérül a ViewModel öröklésekor, amikor a gyermek ViewModel kötelező függőségeket ad hozzá.

kotlin
// ❌ LSP megsértése: Square töri a Rectangle viselkedését
open class Rectangle(open var width: Int, open var height: Int)

class Square(side: Int) : Rectangle(side, side) {
    override var width
        get() = super.width
        set(value) { super.setBoth(value, value) }
}

ISP: Interface Segregation Principle

Interface Segregation Principle (ISP) — az interfészek szétválasztásának elve. Az ügyfelek nem függhetnek olyan interfészektől, amelyeket nem használnak. Egy „kövér” interfész helyett több szűk, specializált interfészt kell létrehozni. Ha egy osztály implementál egy interfészt, de a metódusok egy része UnsupportedOperationException-t dob vagy üres marad — ez az ISP megsértésének egyértelmű jele.

A DigitalOcean, 2024 szerint az ISP különösen releváns a mobilfejlesztésben a ViewModel és a Repository tervezésekor. Egyetlen UserRepository interfész helyett az összes CRUD metódussal jobb létrehozni a QueryUserRepository-t (csak olvasás) és a CommandUserRepository-t (írás). Ekkor az olvasó ügyfél (UI elem) csak a Query interfésztől függ, és nem tud az írási metódusokról.

kotlin
// ❌ Kövér interfész — az ügyfél kénytelen felesleges metódusokat implementálni
interface UserOperations {
    fun getUser(id: String): User
    fun saveUser(user: User)
    fun deleteUser(id: String)
    fun exportUsers(): File
}

// ✅ ISP: szétválasztott interfészek
interface UserReader { fun getUser(id: String): User }
interface UserWriter { fun saveUser(user: User) }
interface UserDeleter { fun deleteUser(id: String) }

DIP: Dependency Inversion Principle

Dependency Inversion Principle (DIP) — a függőségek megfordításának elve. A magas szintű modulok nem függhetnek az alacsony szintű moduloktól. Mindkét szintnek absztrakcióktól (interfészektől) kell függenie. Az absztrakciók nem függhetnek a részletektől — a részletek függnek az absztrakcióktól. Ez nem azonos a „Dependency Injection” (DI) fogalmával, bár a DI a DIP megvalósításának gyakori módja.

A Robert C. Martin, 2019 szerint a DIP a Clean Architecture alapja. A ViewModel (magas szint) nem hozhat létre közvetlenül RetrofitApi (részlet) példányt. Ehelyett a ViewModel a UserRepository interfésztől függ, és a konkrét UserRepositoryImpl implementáció a Retrofit segítségével a konstruktoron keresztül kerül átadásra. Androidban a DIP a Hilt/Dagger vagy Koin segítségével valósul meg: az összes függőséget a DI-tároló biztosítja.

kotlin
// ✅ DIP: A modul absztrakciótól függ, nem részlettől
class UserRepositoryImpl(
    private val api: UserApi,   // Interfésztől függ
    private val db: UserDao     // Interfésztől függ
) : UserRepository {

    override suspend fun getUser(id: String): User {
        return api.fetchUser(id)
    }
}

// Hilt DI: a részletek a DI modulon keresztül kapcsolódnak
@Module
object NetworkModule {
    @Provides
    fun provideUserApi(retrofit: Retrofit): UserApi =
        retrofit.create(UserApi::class.java)
}

A SOLID alkalmazása mobilfejlesztésben

A SOLID a mobilfejlesztésben minden szinten alkalmazásra kerül: az alkalmazás architektúrájától az egyes osztályokig. Android projektekben a Clean Architecture három rétegre osztja a kódot: domain (üzleti logika — független a framework-ektől), data (repository-k, API, DB) és presentation (UI, ViewModel). A domain réteg a SOLID elveket használja: use case (SRP), repository interfészek (DIP), entity osztályok (OCP + LSP).

A Android Developers Guide, 2025 szerint az SRP Androidban a ViewModel, Repository és Mapper szétválasztásában nyilvánul meg. OCP — új adatforrások hozzáadásakor a DataSource interfészen keresztül. LSP — a különböző repository-kból származó Result egységes feldolgozásában. ISP — a CQRS megközelítésben (Read/Write repository-k szétválasztása). DIP — a Hilt/Koin segítségével a függőségek befecskendezéséhez.

ElvProbléma nélküleMegoldás mobil projektben
SRPActivity 1000+ sorralViewModel + UseCase + Repository
OCPswitch-case fizetési típus szerintStrategy: PaymentGateway interfész
LSPHiba a BaseViewModel cseréjekorAlosztályok szerződésének ellenőrzése
ISPUnsupportedOperationExceptionReader / Writer szétválasztás
DIPViewModel kézzel hozza létre a Retrofit-otHilt / Koin DI tároló

Gyakori hibák a SOLID alkalmazásakor

SOLID-hibák legtöbbször a kód túlzott bonyolításához kapcsolódnak. Az első — az elvek szó szerinti betartása a kontextus figyelembevétele nélkül. Egy UserService osztály 10 interfészre és 15 osztályra bontása a „tiszta” ISP érdekében túltervezés. A SOLID egy eszköz, nem cél. A második hiba — az SRP összetévesztése az „egy metódus = egy felelősség” elvvel. Egy osztálynak több metódusa is lehet, ha mind ugyanabba a felelősségi körbe tartozik.

A Simple Thread, 2024 szerint a harmadik hiba — az LSP figyelmen kívül hagyása a ViewModel öröklésekor Androidban. Ha az alap ViewModel LiveData-t vár, és a gyermek StateFlow-t használ — a LiveData-ra feliratkozott ügyfélkód nem kap frissítéseket. A negyedik — a DIP megsértése a tesztelés kedvéért: a RepositoryImpl közvetlenül hozza létre az OkHttpClient példányt, ami lehetetlenné teszi az egységtesztelést.

Arany középút: alkalmazza a SOLID-ot, amikor az valós problémát old meg (gyakori változások, tesztelési nehézségek, ismétlődés). Egyszerű CRUD képernyőkhöz az öt elv szigorú betartása túlzás. Üzleti logika, pénzügyi számítások és API-interakciók esetén a SOLID kötelező.

A SOLID és a Clean Architecture kapcsolata

Clean Architecture (Robert C. Martin, 2012) — a SOLID közvetlen alkalmazása az alkalmazási rétegek szintjén. Az SRP meghatározza a use case határait (minden use case — egy osztály). Az OCP repository interfészeken keresztül valósul meg (a Data réteg változhat a Domain módosítása nélkül). Az ISP biztosítja a Use Case bemeneti/kimeneti boundary-ra bontását. A DIP — a függőségek iránya a Domain réteg belsejébe. Az LSP garantálja, hogy bármely repository implementáció kicserélhető a use case törése nélkül.

Gyakran ismételt kérdések

Mi az a SOLID egyszerű szavakkal?

SOLID — öt szabály a kódíráshoz, hogy a kód könnyen változtatható, tesztelhető és érthető legyen. Minden betű egy elv: ne írjon nagy osztályokat (SRP), ne változtassa a meglévő kódot — adjon hozzá újat (OCP), ne törje meg az öröklők viselkedését (LSP) és többi.

Melyik SOLID elv a legfontosabb?

SRP (Single Responsibility) tekinthető a legfontosabbnak, mert megsértése God-osztályokhoz — nehezen tesztelhető és módosítható hatalmas osztályokhoz vezet. Azonban DIP (Dependency Inversion) nélkül a kód szorosan összekapcsolt marad, ami szintén kritikus.

Kötelező a SOLID a mobilfejlesztésben?

Nem kötelező, de nagyon ajánlott hosszú életciklusú kereskedelmi projektekhez. Egyszerű alkalmazásokhoz (egy képernyő, nincs üzleti logika) a SOLID túlzás lehet. 50+ képernyős és 3+ fejlesztős projektekhez a SOLID a szükséges minimum.

Mi történik, ha nem tartom be a SOLID-ot?

Következmények: az osztályok „kövéré” válnak (1000+ sor), egy helyen történő változtatás három másikat tör el, lehetetlen egységteszteket írni, egy új funkció hozzáadása napok helyett heteket vesz igénybe. Idővel a kód „Big Ball of Mud”-dá — összegabalyodottá és törékennyé válik.

Hogyan ellenőrizhetem, hogy a SOLID-ot betartják a projektben?

A betartás jelei: minden osztály kevesebb mint 200 soros, egy funkció változtatása nem érint 5+ fájlt, a teszteket 10 függőség mockolása nélkül írják, egy új fejlesztő egy nap alatt megérti a struktúrát. Az olyan eszközök, mint a SonarQube és a detekt, segítenek az SRP és DIP megsértéseinek feltárásában.

Összegzés

  • SOLID — öt OOP-elv (SRP, OCP, LSP, ISP, DIP) rugalmas és karbantartható kódhoz
  • SRP — minden entitás egy feladatért felelős, megoldja a God-osztály problémát
  • OCP — bővítés polimorfizmussal, nem a meglévő kód módosításával
  • LSP — az öröklők nem törhetik meg az alaposztály viselkedését
  • ISP — szűk interfészek az univerzális „svájci bicska” helyett
  • DIP — függés absztrakcióktól, befecskendezés Hilt/Koin segítségével Androidban
  • SOLID kötelező a Clean Architecture-hez és kereskedelmi mobil projektekhez

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is