SOLID: principy, 5 pravidel OOP a aplikace ve vývoji

Autor: IT Sectr Publikováno: 2026-05-11 Doba čtení: 10 min

SOLID — pět principů objektově orientovaného programování, formulovaných Robertem C. Martinem (Uncle Bob) na počátku 21. století. Podle DigitalOcean, 2024 se SOLID rozkládá na Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation a Dependency Inversion. Tyto principy tvoří základ Clean Architecture a používají se ve vývoji Android (MVP, MVVM, Clean Architecture) a iOS (VIPER, TCA).

Hlavní

  • SOLID — akronym pěti principů OOP: SRP, OCP, LSP, ISP, DIP, formulovaných Robertem C. Martinem pro vytváření flexibilního a udržovatelného kódu.
  • SRP (Single Responsibility) — každá třída má jeden důvod ke změně, jedna odpovědnost na modul.
  • OCP (Open-Closed) — třídy jsou otevřené pro rozšíření, ale uzavřené pro modifikaci, realizované dědičností a polymorfismem.
  • LSP (Liskov Substitution) — objekty podtříd musí nahrazovat objekty základní třídy bez změny správnosti programu.
  • ISP (Interface Segregation) — klienti by neměli záviset na rozhraních, která nepoužívají, rozhraní by měla být úzká a specifická.
  • DIP (Dependency Inversion) — moduly vyšší úrovně nezávisí na modulech nižší úrovně, oba závisí na abstrakcích.

Co je SOLID? Přehled pěti principů

SOLID — mnemotechnický akronym označující pět principů objektově orientovaného návrhu. Termín zavedl Robert C. Martin v článku „Design Principles and Design Patterns“ (2000) a později popularizoval v knize „Agile Software Development: Principles, Patterns, and Practices“ (2002). SOLID není framework ani knihovna — je to soubor postupů, které dělají kód méně provázaným, lépe testovatelným a snadněji upravitelným.

Podle Clean Coder Blog, 2014, každý princip SOLID řeší konkrétní problém návrhu: SRP bojuje s God-class, OCP — s kaskádovými změnami, LSP — s nesprávnou dědičností, ISP — s tlustými rozhraními, DIP — s těsnou provázaností. Dohromady tvoří základ Clean Architecture, která se používá v Android projektech s MVP, MVVM a MVI.

SRP: Single Responsibility Principle

Single Responsibility Principle (SRP) — princip jedné odpovědnosti. Formulace: „Třída by měla mít jen jeden důvod ke změně.“ To znamená, že každý modul nebo třída je odpovědná za přesně jednu funkcionalitu nebo jednu doménovou entitu. Pokud třída spravuje jak uživatele, tak odesílání e-mailů — má dva důvody ke změně, což porušuje SRP.

Podle Robert C. Martin, 2002, SRP je nejdůležitější a zároveň nejčastěji porušovaný princip. V mobilním vývoji je SRP často porušován v Activity/Fragment, kombinující UI logiku, navigaci, práci se sítí a obchodní logiku. Řešením je oddělení každé vrstvy do samostatné třídy: ViewModel pro UI logiku, Repository pro data, NavController pro navigaci.

Příklad SRP: rozdělení UserManager

Uvažujme třídu UserManager, která načítá profil, ukládá nastavení a odesílá emaily. To jsou tři různé odpovědnosti, každou je třeba oddělit do samostatné třídy: UserProfileRepository (načítání), UserSettingsStorage (ukládání) a EmailService (odesílání). Klientský kód (ViewModel) používá všechny tři pomocí Dependency Injection a každá třída se snadno testuje izolovaně a mění se bez ovlivnění ostatních.

kotlin
// ❌ Porušení SRP: Activity ví o síti, DB a UI
class ProfileActivity : AppCompatActivity() {
    fun loadProfile() {
        api.getUser() // Síťové volání
        db.saveUser()    // Práce s DB
        updateUI()         // Aktualizace UI
    }
}

// ✅ SRP dodržen: vrstvy odděleny
class ProfileViewModel : ViewModel() {
    private val repo = UserRepository()
    fun loadProfile() { repo.getUser() }
}

Známky porušení SRP: třída obsahuje více než 200 řádků, má metody z různých domén, často se mění z různých důvodů. Pro Android vývoj je pravidlo jednoduché: Activity odpovídá pouze za životní cyklus obrazovky, ViewModel — za stav UI, Repository — za zdroje dat.

SRP a mikroservisní architektura

Princip SRP se vztahuje nejen na třídy, ale i na architekturu na úrovni služeb. Každá mikroslužba je odpovědná za jednu doménovou entitu: UserService — pouze uživatelé, PaymentService — pouze platby, NotificationService — pouze oznámení. To umožňuje škálování, nasazování a testování služeb nezávisle. V mobilní aplikaci se SRP na úrovni mikroslužeb projevuje v rozdělení API klientů podle domén.

OCP: Open-Closed Principle

Open-Closed Principle (OCP) — princip otevřenosti/uzavřenosti. Třídy by měly být otevřené pro rozšíření (lze přidat nové chování) a uzavřené pro modifikaci (stávající kód se nemění). Dosahuje se polymorfismem, abstraktními třídami a rozhraními. Namísto přidávání if-else do stávající metody se vytváří nová implementace rozhraní.

Podle Clean Coder Blog, 2014, OCP je nejúčinnější v kombinaci se vzorem Strategy. Například, pokud aplikace podporuje různé platební metody (Google Pay, Apple Pay, PayPal), není třeba přidávat switch-case do platebního procesoru. Každá platební metoda implementuje společné rozhraní PaymentGateway a nový platební systém se přidá jako nová třída beze změny stávajícího kódu.

kotlin
// ✅ OCP: otevřený pro rozšíření, uzavřený pro modifikaci
interface PaymentGateway {
    fun processPayment(amount: Double): Boolean
}

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

// Nový platební systém — beze změny stávajícího kódu
class ApplePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

LSP: Liskov Substitution Principle

Liskov Substitution Principle (LSP) — princip substituce Barbary Liskovové. Pokud je S podtypem T, pak objekty T lze nahradit objekty S beze změny vlastností programu. Formálně: funkce používající základní třídu by měla pracovat správně s libovolnou její podtřídou. Pokud podtřída vyhazuje výjimku tam, kde základní třída ne — LSP je porušen.

Podle Robert C. Martin, 2002, LSP je nejobtížněji pochopitelný princip SOLID. Klasický příklad porušení — třída Square (čtverec) dědící z Rectangle (obdélník). Pokud setWidth pro Square nastavuje šířku i výšku, klientský kód očekávající chování Rectangle dostane neočekávaný výsledek. V mobilním vývoji je LSP často porušován při dědění ViewModel, když podřízený ViewModel přidává povinné závislosti.

kotlin
// ❌ Porušení LSP: Square láme chování Rectangle
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) — princip segregace rozhraní. Klienti by neměli záviset na rozhraních, která nepoužívají. Místo jednoho „tlustého“ rozhraní se vytváří několik úzkých specializovaných. Pokud třída implementuje rozhraní, ale část metod vyhazuje výjimku UnsupportedOperationException nebo zůstává prázdná — to je jasný znak porušení ISP.

Podle DigitalOcean, 2024, ISP je obzvláště relevantní v mobilním vývoji při navrhování ViewModel a Repository. Místo jednoho rozhraní UserRepository se všemi CRUD metodami je lepší vytvořit QueryUserRepository (pouze čtení) a CommandUserRepository (zápis). Pak čtecí klient (UI prvek) závisí pouze na rozhraní Query a neví o metodách zápisu.

kotlin
// ❌ Tlusté rozhraní — klient nucen implementovat zbytečné metody
interface UserOperations {
    fun getUser(id: String): User
    fun saveUser(user: User)
    fun deleteUser(id: String)
    fun exportUsers(): File
}

// ✅ ISP: oddělená rozhraní
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) — princip obrácení závislostí. Moduly vyšší úrovně by neměly záviset na modulech nižší úrovně. Obě úrovně by měly záviset na abstrakcích (rozhraních). Abstrakce by neměly záviset na detailech — detaily závisí na abstrakcích. To není totéž co „Dependency Injection“ (vkládání závislostí), ačkoli DI je častý způsob implementace DIP.

Podle Robert C. Martin, 2019, DIP je základem Clean Architecture. ViewModel (vyšší úroveň) by neměl přímo vytvářet instanci RetrofitApi (detail). Místo toho ViewModel závisí na rozhraní UserRepository a konkrétní implementace UserRepositoryImpl s Retrofit je předána přes konstruktor. V Androidu se DIP implementuje pomocí Hilt/Dagger nebo Koin: všechny závislosti jsou poskytovány přes DI kontejner.

kotlin
// ✅ DIP: Modul závisí na abstrakci, ne na detailu
class UserRepositoryImpl(
    private val api: UserApi,   // Závisí na rozhraní
    private val db: UserDao     // Závisí na rozhraní
) : UserRepository {

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

// Hilt DI: detaily jsou propojeny přes DI modul
@Module
object NetworkModule {
    @Provides
    fun provideUserApi(retrofit: Retrofit): UserApi =
        retrofit.create(UserApi::class.java)
}

Aplikace SOLID v mobilním vývoji

SOLID v mobilním vývoji se aplikuje na všech úrovních: od architektury aplikace po jednotlivé třídy. V Android projektech Clean Architecture dělí kód do tří vrstev: domain (obchodní logika — nezávislá na frameworkách), data (repozitáře, API, DB) a presentation (UI, ViewModel). Vrstva domain používá principy SOLID: use case (SRP), rozhraní repozitářů (DIP), entity třídy (OCP + LSP).

Podle Android Developers Guide, 2025, SRP se v Androidu projevuje v rozdělení ViewModel, Repository a Mapper. OCP — při přidávání nových zdrojů dat přes rozhraní DataSource. LSP — v jednotném zpracování Result z různých repozitářů. ISP — v přístupu CQRS (oddělení repozitářů Read/Write). DIP — přes Hilt/Koin pro vkládání závislostí.

PrincipProblém bez nějŘešení v mobilním projektu
SRPActivity na 1000+ řádkůViewModel + UseCase + Repository
OCPswitch-case podle typu platbyStrategy: rozhraní PaymentGateway
LSPChyba při záměně BaseViewModelKontrola kontraktu podtříd
ISPUnsupportedOperationExceptionOddělení Reader / Writer
DIPViewModel ručně vytváří RetrofitDI kontejner Hilt / Koin

Typické chyby při aplikaci SOLID

Chyby SOLID jsou nejčastěji spojeny s nadměrným komplikováním kódu. První — doslovné dodržování principů bez ohledu na kontext. Rozdělení jedné třídy UserService do 10 rozhraní a 15 tříd kvůli „čistému“ ISP je overengineering. SOLID je nástroj, ne cíl. Druhá chyba — záměna SRP s „jedna metoda = jedna odpovědnost“. Třída může mít více metod, pokud všechny patří do jedné oblasti odpovědnosti.

Podle Simple Thread, 2024, třetí chyba — ignorování LSP při dědění ViewModel v Androidu. Pokud základní ViewModel očekává LiveData a podřízený používá StateFlow — klientský kód přihlášený k LiveData nedostane aktualizace. Čtvrtá — porušení DIP kvůli testování: RepositoryImpl přímo vytváří instanci OkHttpClient, což znemožňuje unit testování.

Zlaté pravidlo: aplikujte SOLID, když řeší skutečný problém (časté změny, obtížné testování, duplicita). Pro jednoduché CRUD obrazovky je striktní dodržování všech pěti principů přehnané. Pro obchodní logiku, finanční výpočty a API interakce je SOLID povinný.

Spojení SOLID a Clean Architecture

Clean Architecture (Robert C. Martin, 2012) — přímá aplikace SOLID na úrovni vrstev aplikace. SRP určuje hranice use case (každý use case — jedna třída). OCP je realizován přes rozhraní repozitářů (vrstva Data se může měnit beze změny Domain). ISP poskytuje rozdělení Use Case na vstupní/výstupní hranici. DIP — směr závislostí dovnitř vrstvy Domain. LSP zaručuje, že jakákoli implementace repozitáře je zaměnitelná bez narušení use case.

Často kladené otázky

Co je SOLID jednoduše řečeno?

SOLID — pět pravidel psaní kódu, aby byl snadno měnitelný, testovatelný a srozumitelný. Každé písmeno je jeden princip: nepište velké třídy (SRP), neměňte stávající kód — přidávejte nový (OCP), nelámejte chování dědiců (LSP) a další.

Který princip SOLID je nejdůležitější?

SRP (Single Responsibility) je považován za nejdůležitější, protože jeho porušení vede k God-class — obrovským třídám, které je obtížné testovat a měnit. Bez DIP (Dependency Inversion) však zůstává kód těsně provázaný, což je také kritické.

Je SOLID povinný pro mobilní vývoj?

Není povinný, ale velmi doporučovaný pro komerční projekty s dlouhým životním cyklem. Pro jednoduché aplikace (jedna obrazovka, bez obchodní logiky) může být SOLID přehnaný. Pro projekty s 50+ obrazovkami a 3+ vývojáři je SOLID nezbytné minimum.

Co se stane, když SOLID nedodržuji?

Důsledky: třídy „tloustnou“ (1000+ řádků), změna na jednom místě láme tři další, není možné psát unit testy, přidání nové funkce trvá týdny místo dnů. Časem se kód mění v „Big Ball of Mud“ — zamotaný a křehký.

Jak zkontrolovat, zda je SOLID v projektu dodržován?

Známky dodržování: každá třída má méně než 200 řádků, změna funkce neovlivní 5+ souborů, testy se píší bez mockování 10 závislostí, nový vývojář pochopí strukturu za den. Nástroje jako SonarQube a detekt pomáhají odhalit porušení SRP a DIP.

Shrnutí

  • SOLID — pět OOP principů (SRP, OCP, LSP, ISP, DIP) pro flexibilní a udržovatelný kód
  • SRP — každá entita odpovídá za jeden úkol, řeší problém God-class
  • OCP — rozšíření polymorfismem, ne modifikací stávajícího kódu
  • LSP — dědicové by neměli lámat chování základní třídy
  • ISP — úzká rozhraní místo univerzálního „švýcarského nože“
  • DIP — závislost na abstrakcích, vkládání přes Hilt/Koin v Androidu
  • SOLID je povinný pro Clean Architecture a komerční mobilní projekty

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také