Por que tantos têm problemas com esse princípio? Se tomarmos não "obscuro", mas uma definição mais simples, então soa assim:
A classe herdada deve complementar, não substituir, o comportamento da classe base.
Parece claro e bastante lógico, discordamos. mas como conseguir isso? Por alguma razão, muitas pessoas simplesmente ignoram as informações sobre pré - condições e pós - condições , que explicam perfeitamente o que precisa ser feito.
Neste artigo, NÃO vamos considerar exemplos gerais deste princípio, sobre o qual já existem muitos materiais (exemplo com um quadrado e um retângulo ou controles de termostato ). Aqui nos deteremos com um pouco mais de detalhes em conceitos como "Pré-condições" , "Pós-condições" , considerar o que são covariância, contravariância e invariância , bem como o que são "restrições históricas" ou "regra da história".
As pré-condições não podem ser reforçadas em uma subclasse
️ Em outras palavras, as classes filhas não devem criar mais pré-condições do que as definidas na classe base para realizar algum comportamento de negócios. Aqui está um exemplo:
<?php
class Customer
{
protected float $account = 0;
public function putMoneyIntoAccount(int|float $sum): void
{
if ($sum < 1) {
throw new Exception(' 1$');
}
$this->account += $sum;
}
}
class MicroCustomer extends Customer
{
public function putMoneyIntoAccount(int|float $sum): void
{
if ($sum < 1) {
throw new Exception(' 1$');
}
//
if ($sum > 100) {
throw new Exception(' 100$');
}
$this->account += $sum;
}
}
. !
«», , .
, , .
, , Bar->process()
, .
<?php
class Foo
{
public function process(int|float $value)
{
// some code
}
}
class Bar extends Foo
{
public function process(int|float|string $value)
{
// some code
}
}
, VIPCustomer
putMoneyIntoAccount
( ) Money
, ( Dollars
).
<?php
class Money {}
class Dollars extends Money {}
class Customer
{
protected Money $account;
public function putMoneyIntoAccount(Dollars $sum): void
{
$this->account = $sum;
}
}
class VIPCustomer extends Customer
{
public function putMoneyIntoAccount(Money $sum): void
{
$this->account = $sum;
}
}
, , .
️ , . .
<?php
class Customer
{
protected Dollars $account;
public function chargeMoney(Dollars $sum): float
{
$result = $this->account - $sum->getAmount();
if ($result < 0) { //
throw new Exception();
}
return $result;
}
}
class VIPCustomer extends Customer
{
public function chargeMoney(Dollars $sum): float
{
$result = $this->account - $sum->getAmount();
if ($sum < 1000) { //
$result -= 5;
}
//
return $result;
}
}
, . !
- «», (?!), .
. render()
, JpgImage
, Image
, Renderer
.
<?php
class Image {}
class JpgImage extends Image {}
class Renderer
{
public function render(): Image
{
}
}
class PhotoRenderer extends Renderer
{
public function render(): JpgImage
{
}
}
️ . . :)
.
- .
— , . , .
.
<?php
class Wallet
{
protected float $amount;
//
}
(« »):
.
, . , .
<?php
class Deposit
{
protected float $account = 0;
public function __construct(float $sum)
{
if ($sum < 0) {
throw new Exception(' ');
}
$this->account += $sum;
}
}
class VipDeposit extends Deposit
{
public function getMoney(float $sum)
{
$this->account -= $sum;
}
}
Deposit
. VipDeposit
, account
, Deposit
. .
.
, , , , .
Vale ressaltar que devemos nos esforçar para nos livrarmos das condições pré / pós. Idealmente, eles devem ser definidos como parâmetros de entrada / saída do método (por exemplo, passando objetos de valor prontos para a assinatura e retornando um objeto válido específico para a saída).
Espero que tenha sido útil.