ISP — co to je, princip rozdělení rozhraní ve vývoji

Autor: IT Sectr Publikováno: 2026-05-12 Doba čtení: 9 min

ISP (Interface Segregation Principle) — čtvrtý princip SOLID, který tvrdí: klienti by neměli záviset na metodách, které nepoužívají. Princip byl formulován Robertem Martinem v kontextu navrhování rozhraní pro objektově orientované systémy. Jak je popsáno v knize Clean Architecture (2017), princip rozdělení rozhraní vyžaduje vytváření úzce specializovaných rozhraní místo jednoho univerzálního, což snižuje provázanost a zjednodušuje provádění změn.

Hlavní

  • ISP — princip rozdělení rozhraní, čtvrtý v SOLID
  • Klienti by neměli záviset na metodách, které nevolají
  • Tlustá rozhraní (Fat Interfaces) obsahují metody irelevantní pro část klientů
  • Dělení rozhraní snižuje provázanost a zvyšuje znovupoužití kódu
  • ISP je úzce spojen s SRP a Single Responsibility na úrovni rozhraní

Co je ISP (Interface Segregation Principle)?

ISP (Interface Segregation Principle) — princip rozdělení rozhraní, který zakazuje vytváření „tlustých” rozhraní s metodami, které nejsou používány všemi klienty. Místo jednoho rozhraní s deseti metodami je navrženo několik malých rozhraní, každé pro svou skupinu klientů.

Princip byl zaveden Robertem Martinem jako řešení problému „znečištění rozhraní”, když je třída nucena implementovat metody, které nepotřebuje, jen proto, že jsou deklarovány ve společném rozhraní. Ve staticky typovaných jazycích to vede k prázdným implementacím nebo vyhazování výjimek — přímý znak porušení ISP.

ISP a SRP se doplňují: SRP se týká odpovědnosti třídy, ISP se týká kontraktů rozhraní. SRP říká „jedna třída — jeden důvod ke změně”, ISP říká „jedno rozhraní — jeden klientský scénář”. Společně tvoří modulární architekturu, kde každý prvek systému má jasné hranice.

Tlustá rozhraní a jejich důsledky

Fat Interface — rozhraní obsahující více metod, než potřebuje konkrétní klient. Například rozhraní Worker s metodami work, eat, sleep. Robotický pracovník by neměl implementovat eat a sleep, ale je nucen. Řešení — rozdělení na Workable, Eatable, Sleepable. Každý klient dostane přesně to, co potřebuje.

V mobilním vývoji se tlustá rozhraní vyskytují v protokolech delegátů a DataSource. Jeden protokol může obsahovat metody pro dva různé scénáře (úpravy + zobrazení), i když konkrétní obrazovka používá pouze jeden z nich.

Jak funguje princip rozdělení rozhraní

Implementace ISP začíná analýzou klientů každého rozhraní. Pokud dva klienti používají různé sady metod stejného rozhraní — rozhraní by mělo být rozděleno. Každé nové rozhraní seskupuje metody, které jsou volány společně v rámci jednoho scénáře.

Mechanismus rozdělení: původní rozhraní je rozděleno na několik úzkých, z nichž každé dědí společnou část (pokud existuje). Klienti přecházejí na závislost na potřebném úzkém rozhraní místo obecného. Třídy, které implementovaly původní rozhraní, nyní implementují pouze ta úzká rozhraní, která skutečně potřebují.

Důležité upřesnění: stupeň rozdělení je určen počtem klientů a jejich scénářů. ISP nevyžaduje maximální rozdělení (mikrorozhraní s jednou metodou). To by vedlo k nadměrné složitosti. Cílem je odstranit závislost klientů na zbytečných metodách, nikoli minimalizovat velikost každého rozhraní.

Známky porušení ISP

Hlavní známky porušení ISP zahrnují: třídy implementující rozhraní s prázdnými metodami (fiktivní implementace), vyhazování výjimky UnsupportedOperationException v implementacích, velký počet parametrů nebo návratových typů, které nejsou používány částí klientů, a časté změny rozhraní postihující pouze část klientů.

Ve vývoji pro Android je typickým příkladem porušení ISP rozhraní OnItemClickListener, které zahrnuje metody pro kliknutí, dlouhé kliknutí a přejetí. Pokud konkrétní obrazovka používá pouze kliknutí — zbývající metody zůstávají prázdné. Řešení — rozdělení na OnItemClickListener, OnItemLongClickListener, OnItemSwipeListener.

Ve vývoji pro iOS se porušení ISP projevuje v delegátech UIKit: jeden protokol obsahuje metody pro různé stavy komponenty. UITableViewDelegate zahrnuje metody pro zobrazení, výběr, úpravy a akce přejetí. Často vývojáři implementují celý protokol s deseti prázdnými metodami. Rozdělení do několika protokolů podle skupin odpovědnosti řeší problém.

Závislost na nepoužívaných metodách

Problém není jen v estetice kódu. Když se rozhraní změní (přidá se nová metoda), všechny implementující třídy musí být aktualizovány — i ty, které novou metodu nepotřebují. V mobilním vývoji s desítkami obrazovek to vede k kaskádovým změnám. ISP izoluje každého klienta od změn, které se ho netýkají.

Implicitní porušení ISP nastává prostřednictvím konfiguračních parametrů. Pokud metoda přijímá objekt s velkým počtem polí, zatímco klient používá pouze 2-3 z nich — to je signál k rozdělení. Alternativa: několik specializovaných metod s minimální sadou parametrů.

Ve vývoji pro Android je ISP porušován při použití jednoho SharedPreferencesManager pro čtení a zápis všech nastavení aplikace. Fragment, který potřebuje pouze přečíst téma, získává závislost na globálním správci s desítkami metod pro různé typy dat. Rozdělení na ThemePreferenceProvider, AuthPreferenceProvider, FeatureFlagProvider — aplikace ISP na úrovni konfiguračních služeb. Každý poskytovatel obsahuje přesně ty metody, které jeho klienti potřebují.

Příklady ISP v mobilních aplikacích

Podívejme se na příklad z Androidu s rozhraním pro práci s daty. Porušení ISP — jedno rozhraní pro všechny CRUD operace, i když ne všichni klienti potřebují všechny operace.

kotlin
// Porušení ISP: tlusté rozhraní
interface UserRepository {
    fun getAll(): List<User>
    fun getById(id: Int): User
    fun save(user: User)
    fun delete(id: Int)
}

// Po aplikaci ISP: úzká rozhraní
interface UserReader {
    fun getAll(): List<User>
    fun getById(id: Int): User
}

interface UserWriter {
    fun save(user: User)
    fun delete(id: Int)
}

// ReadOnlyViewModel nezávisí na metodách zápisu
class ReadOnlyViewModel(
    private val reader: UserReader
)

Příklad z iOS s rozdělením protokolů pro práci s médii:

swift
// Porušení ISP: jeden protokol pro celou práci s médii
protocol MediaService {
    func play(url: URL)
    func pause()
    func stop()
    func upload(data: Data) async -> URL
    func download(url: URL) async -> Data
}

// Po ISP: rozdělení na protokoly podle odpovědnosti
protocol MediaPlayer {
    func play(url: URL)
    func pause()
    func stop()
}

protocol MediaTransfer {
    func upload(data: Data) async -> URL
    func download(url: URL) async -> Data
}

// PlayerViewModel nezávisí na metodách načítání
class PlayerViewModel {
    private let player: MediaPlayer
}

Praktický závěr: ISP chrání klienty před změnami v nezávislých částech rozhraní. Rozdělení UserRepository na UserReader a UserWriter znamená, že změny v save neovlivňují ReadOnlyViewModel a naopak. Každý klient je izolován od funkčnosti, kterou nepoužívá, a nevyžaduje změny při vylepšování jiných částí systému.

ISP a SRP — přirozený pár. SRP určuje, že třída by měla mít jeden důvod ke změně. ISP aplikuje stejnou logiku na rozhraní: rozhraní by mělo obsluhovat jeden klientský scénář. Třída může implementovat několik úzkých rozhraní (každé odpovídá jedné odpovědnosti), což je čistší než jedno tlusté rozhraní s více odpovědnostmi.

ISP a OCP jsou také propojeny: úzká rozhraní se snadněji rozšiřují. Přidání nové metody do úzkého rozhraní postihuje pouze jeho klienty. Přidání metody do tlustého rozhraní postihuje všechny klienty — potenciálně porušuje OCP, pokud jsou klienti nuceni změnit svou implementaci.

ISP a DIP spolupracují: DIP vyžaduje závislost na abstrakcích. ISP činí tyto abstrakce úzkými a zaměřenými. Závislost na širokém rozhraní je stále závislost na abstrakci, ale „špatné” abstrakci z pohledu ISP. Čtyři principy (SRP, OCP, ISP, DIP) tvoří „pyramidu modularity”: SRP a ISP určují hranice, OCP a DIP — způsoby rozšiřování a propojování.

Aplikace ISP v komponentové architektuře

Komponentová architektura v mobilních projektech (moduly, funkce, vrstvy) těží z ISP na úrovni veřejných API. Každý modul exportuje úzká rozhraní pro své spotřebitele, nikoli jednu společnou fasádu. To umožňuje měnit vnitřní implementaci modulu bez ovlivnění spotřebitelů, kteří používají pouze část jeho funkčnosti.

V projektech pro Android s Clean Architecture je ISP aplikován na UseCase: každý UseCase je samostatné rozhraní s jednou metodou invoke nebo execute. Klient (ViewModel) závisí pouze na UseCase, který potřebuje, nikoli na celém repozitáři. To činí závislosti transparentními a testovatelnými.

Často kladené otázky

Vede ISP k nadměrnému počtu rozhraní?

Ano, nadměrné dělení je možné. ISP nevyžaduje jedno rozhraní na každou metodu. Kritérium: existuje klient, který potřebuje pouze část metod rozhraní? Pokud všichni klienti používají všechny metody — rozhraní není třeba dělit. Optimální úroveň dělení určují reálné scénáře použití.

Jak se ISP aplikuje na parametry funkcí?

ISP na úrovni parametrů znamená: funkce by neměla přijímat objekty s velkým počtem polí, pokud používá pouze část z nich. Místo toho by měla být předávána pouze potřebná data nebo použita specializovaná rozhraní (například rozhraní Renderable místo plného User).

Čím se ISP liší od LSP?

LSP se týká správné dědičnosti a behaviorální kompatibility podtypů. ISP se týká navrhování rozhraní: klienti by neměli záviset na metodách, které nepoužívají. LSP odpovídá na otázku „lze použít podtřídu místo základní třídy?”, ISP — „potřebuje klient celé rozhraní?”.

Jak ISP zjednodušuje testování?

Úzká rozhraní zjednodušují vytváření mock objektů: test vytváří mock s jednou nebo dvěma metodami, nikoli s deseti. Čím méně metod v rozhraní, tím snazší je simulovat jeho chování. To snižuje kognitivní zátěž vývojáře testu a snižuje pravděpodobnost chyb v mock logice.

Kdy lze od ISP odstoupit?

Pokud je rozhraní stabilní a všichni klienti používají všechny metody — dělení je nadbytečné. Typický příklad: protokoly UIKit navržené Apple. Jejich dělení je riskantní, protože UIKit očekává úplnou implementaci delegáta. V takových případech je porušení ISP ospravedlněno stabilitou API.

Shrnutí

  • ISP (Interface Segregation Principle) — princip rozdělení rozhraní, čtvrtý v SOLID
  • Klient by neměl záviset na metodách, které nepoužívá
  • Tlustá rozhraní nutí třídy implementovat zbytečné metody jako prázdné nebo s výjimkami
  • Rozdělení rozhraní snižuje provázanost a izoluje klienty od změn
  • ISP + SRP tvoří hranice modulů: jedna odpovědnost — jeden úzký kontrakt
  • Mock testování se zjednodušuje: úzké rozhraní vyžaduje méně simulací
  • Optimální dělení určují reálné klientské scénáře, nikoli maximální dělení

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é