Pourquoi tant de gens ont-ils des problèmes avec ce principe? Si nous ne prenons pas «abstrus», mais une définition plus simple, alors cela ressemble à ceci:
La classe héritière doit compléter, et non remplacer, le comportement de la classe de base.
Cela semble clair et assez logique, nous ne sommes pas d'accord. mais putain comment y parvenir? Pour une raison quelconque, de nombreuses personnes ignorent simplement les informations sur les conditions préalables et les post - conditions , qui expliquent parfaitement ce qui doit être fait.
Dans cet article, nous ne considérerons PAS d'exemples généraux de ce principe, sur lequel il existe déjà de nombreux matériaux (exemple avec un carré et un rectangle ou des commandes de thermostat ). Ici, nous nous attarderons un peu plus en détail sur des concepts tels que «Préconditions» , «Postconditions» , examinerons ce que sont la covariance, la contravariance et l'invariance , ainsi que ce que sont les «contraintes historiques» ou «règle de l'histoire».
Les conditions préalables ne peuvent pas être renforcées dans une sous-classe
️ En d'autres termes, les classes enfants ne doivent pas créer plus de conditions préalables que celles définies dans la classe de base afin d'effectuer certains comportements commerciaux. Voici un exemple:
<?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
. .
.
, , , , .
Il convient de mentionner qu'il faut s'efforcer de se débarrasser des conditions pré / post. Idéalement, ils devraient être définis comme des paramètres d'entrée / sortie de la méthode (par exemple, en passant des objets de valeur prêts à l'emploi à la signature et en renvoyant un objet valide spécifique à la sortie).
J'espère que cela a été utile.