¿Por qué tantos tienen problemas con este principio? Si no tomamos "abstruso", sino una definición más simple, entonces suena así:
La clase heredada debe complementar, no anular, el comportamiento de la clase base.
Suena claro y bastante lógico, no estamos de acuerdo. pero maldita sea, ¿cómo lograr esto? Por alguna razón, muchas personas simplemente omiten información sobre condiciones previas y posteriores , que explican perfectamente lo que se debe hacer.
En este artículo, NO consideraremos ejemplos generales de este principio, sobre el cual ya existen muchos materiales (ejemplo con un cuadrado y un rectángulo o controles de termostato ). Aquí nos detendremos con un poco más de detalle en conceptos tales como "Precondiciones" , "Poscondiciones" , consideraremos qué son la covarianza, contravarianza e invariancia , así como qué son las "limitaciones históricas" o la "regla de la historia".
Las condiciones previas no se pueden reforzar en una subclase
️En otras palabras, las clases secundarias no deben crear más condiciones previas que las definidas en la clase base para realizar algún comportamiento comercial. He aquí un ejemplo:
<?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 la pena mencionar que debe esforzarse por deshacerse de las condiciones previas y posteriores. Idealmente, deberían definirse como parámetros de entrada / salida del método (por ejemplo, pasando objetos de valor listos para usar a la firma y devolviendo un objeto válido específico a la salida).
Espero que haya sido útil.