Slovník pojmů
Rozhraní v programování
Rozhraní popisuje, co objekt umí, ne jak to uvnitř provádí. Díky tomu lze spolupracující část systému vyměnit, testovat nebo provozovat jiným způsobem bez změny jejího konzumenta.
Stručná definice
Kontrakt odděluje schopnost od jedné konkrétní třídy.
Interface deklaruje veřejné metody a jejich kompatibilní signatury; implementující třída doplní vlastní chování. Jedna třída může implementovat více rozhraní a více tříd může poskytovat stejný kontrakt. Volající pak typuje závislost rozhraním, pokud mu stačí popsaná schopnost.
Rozhraní v programovacím jazyce není totéž co uživatelské rozhraní ani HTTP API. Všechny tři pojmy vyjadřují hranici komunikace, ale PHP interface je konkrétní jazykový kontrakt mezi třídami. Vedle metod může PHP rozhraní deklarovat také konstanty a v současném PHP i požadavky na veřejně přístupné vlastnosti.
Použití
Kde kontrakt skutečně snižuje vazbu
Rozhraní je užitečné tam, kde má více implementací stejný význam pro konzumenta, nikoli jako povinný doplněk každé třídy.
- dopravci, kteří vytvoří štítek zásilky společným způsobem
- skladové brány pro lokální systém i vzdálené API
- úložiště, cache nebo fronta vyměnitelná podle prostředí
- test double nahrazující pomalou nebo placenou externí službu
- aplikační port mezi doménovou logikou a infrastrukturou
Praktický příklad
Založení zásilky přes společný kontrakt
Checkout nemusí vědět, jestli dopravce komunikuje přes REST API, SOAP nebo lokální knihovnu. Požaduje pouze schopnost vytvořit štítek. Implementaci zvolí konfigurace aplikace; test může použít jednoduchý fake bez sítě.
PHP
interface ShippingLabelProvider
{
public function create(Shipment $shipment): ShippingLabel;
}
final class CreateShipment
{
public function __construct(private ShippingLabelProvider $labels)
{
}
public function handle(Shipment $shipment): ShippingLabel
{
return $this->labels->create($shipment);
}
}
Jak to funguje
Od potřebné schopnosti ke konkrétnímu adaptéru
Rozhraní stojí mezi částí aplikace, která práci potřebuje, a částí, která ji technicky provede.
- Pojmenování kontraktu Rozhraní vyjadřuje jednu smysluplnou schopnost, například vytvoření štítku.
- Implementace Třída dodrží metody a jejich signatury, ale volí vlastní technické provedení.
- Předání závislosti Aplikační služba dostane kontrakt přes konstruktor nebo DI container.
- Volání Konzument pracuje jen s metodami rozhraní, ne s detaily dopravce.
- Výměna a test Implementaci lze nahradit jiným adaptérem nebo testovacím fakem při zachování významu kontraktu.
Hlavní části a pojmy
Rozhraní popisuje veřejné chování, ne celý objekt.
Dobře navržený kontrakt je úzký, stabilní a mluví jazykem konkrétního problému.
Implementace
Klíčové slovo implements zavazuje třídu doplnit požadované veřejné metody s kompatibilní signaturou.
Polymorfismus
Různé objekty lze používat zaměnitelně, pokud pro konzumenta dodržují stejný význam kontraktu.
Více rozhraní
Třída může implementovat více samostatných schopností. To je jiné než vícenásobná dědičnost tříd, kterou PHP nepodporuje.
Rozhraní a abstraktní třída
Abstraktní třída může sdílet částečnou implementaci a stav. Rozhraní se soustředí na veřejný kontrakt a nevnucuje dědičnou větev.
Kontrakt a API
V obou případech jde o dohodu mezi stranami. PHP interface ale běžně není veřejné HTTP API pro jiné systémy.
Vztah k architektuře
Rozhraní pomáhá na hranici, ne jako dekorace každého souboru.
Nejužitečnější bývá tam, kde se mění technický detail nebo kde se vyplatí nezávisle ověřit spolupráci.
- Dependency Injection
- Konzument může záviset na kontraktu a konkrétní implementaci obdrží při sestavení aplikace.
- Test double
- Fake nebo stub dodá předvídatelný výsledek; mock ověřuje vybranou spolupráci, pokud je její volání podstatné.
- Port a adaptér
- Aplikační vrstva může definovat port jako rozhraní a infrastruktura k němu dodat adaptér.
- Veřejná knihovna
- Stabilní interface je závazek vůči uživatelům knihovny, proto se jeho změna zvažuje pečlivěji než interní třída.
Výhody a omezení
Interface snižuje vazbu, ale nezlepší špatně zvolený kontrakt.
Přínosy
- konzument nezná konkrétní technické provedení
- výměna implementace může mít malý dopad na zbytek kódu
- test se snadněji izoluje od externí infrastruktury
- kontrakt zpřesňuje očekávané schopnosti objektu
Časté chyby
- interface pro každou interní třídu bez druhého konzumenta či alternativy
- příliš široký kontrakt se směsí nesouvisejících metod
- rozhraní kopírující technický detail místo obchodní potřeby
- představa, že interface sám zajistí dobrou architekturu nebo testy
Kdy dává smysl
Používat, když kontrakt odpovídá skutečné variabilitě.
Rozhraní má dobrý důvod například u dopravců, platebních bran, úložišť a integračních klientů, kde může aplikace používat více implementací stejné schopnosti. Užitečné je také tehdy, když aplikační vrstva nemá znát detail databáze nebo sítě.
Jedna interní třída bez plánované výměny často interface nepotřebuje. Nejprve je vhodné pojmenovat konkrétní potřebu; abstrakci lze přidat ve chvíli, kdy rozhraní chrání reálnou hranici, ne jen hypotetickou budoucnost.
Na co myslet
Kontrakt má být malý, významový a ověřitelný.
Při změně rozhraní je dobré myslet na všechny implementace i na význam výsledku, ne pouze na shodu názvů metod.
- typovat závislost nejmenším kontraktem, který konzument skutečně potřebuje
- držet stejné názvy parametrů u implementace, zejména při použití pojmenovaných argumentů
- nepřidávat metodu jen proto, že ji potřebuje jedna nesouvisející implementace
- testovat pozorovatelný význam kontraktu napříč implementacemi
- nenahrazovat rozhraním přímou a jednodušší spolupráci bez důvodu
Časté otázky
Rozhraní neboli interface v PHP
Jaký je rozdíl mezi rozhraním a třídou?
Třída dodává konkrétní stav a chování. Rozhraní především předepisuje veřejný kontrakt, který musí implementující třída dodržet.
Musí mít každá třída vlastní interface?
Ne. Smysl má při skutečném kontraktu, více implementacích nebo jasné architektonické hranici. Pro jednu interní třídu bez takové potřeby jen přidává údržbu.
Může třída implementovat více rozhraní?
Ano. PHP umožňuje implementovat více rozhraní; třída pak musí splnit kontrakty všech jejich veřejných metod.
Je interface totéž co dependency injection?
Ne. Rozhraní popisuje kontrakt. Dependency injection je způsob, jak objekt dostane závislost zvenčí; může jí být interface i konkrétní třída.
Jak navrhuji aplikace v praxi
Kontrakty zavádím tam, kde zjednoduší změnu nebo oddělí infrastrukturu.
U složitějších PHP aplikací rozlišuji aplikační rozhodnutí od databáze, HTTP a externích služeb; rozsah oddělení vždy volím podle konkrétního problému.