Cílem tohoto principu je, aby podtřídy zůstaly kompatibilní s chováním nadřazené třídy. Podtřídy by měly rozšiřovat chování rodičovské třídy a ne ji nahrazovat něčím jiným.
Pokud se budete řídit tímto principem, budete moci nahradit nadřazenou třídu kteroukoli z jejích podtříd, aniž by došlo k porušení kódu klienta .
Představte si, že máme aplikaci, která přijímá objednávky. Pro objednávku existují dva možné stavy:koncept nebo potvrzeno. Pokud nebyla objednávka potvrzena, nelze ji zaplatit.
V následujícím příkladu porušujeme princip substituce, protože nadřazená třída má metodu markAsPaid
který nevyvolává žádné chyby. Naopak podtřída DraftOrder
vyvolá chybu v této metodě, protože koncept objednávek nelze zaplatit. Nahrazení nadřazené třídy Order
podle jeho podtřídy DraftOrder
může prolomit kód, pokud bychom volali markAsPaid
.
class Order {
id: number;
items: string[];
payed: boolean;
// constructor
markAsPaid(): void {
this.payed = true;
}
}
class DraftOrder extends Order {
markAsPaid(): void {
throw new Error("Draft orders can't be payed");
}
}
Můžeme to zlepšit tím, že koncept objednávek uděláme nadřazenou třídou a potvrzené objednávky podtřídou. Tímto způsobem je možné nahradit nadřazenou třídu podtřídou bez porušení kódu.
class Order {
id: number;
items: string[];
// constructor
}
class ConfirmedOrder extends Order {
payed: boolean;
// constructor
markAsPaid(): void {
this.payed = true;
}
}