なぜそんなに多くの人がこの原則に問題を抱えているのですか?「乱暴」ではなく、より単純な定義をとると、次のようになります。
継承クラスは、基本クラスの動作をオーバーライドするのではなく、補完する必要があります。
それは明確で非常に論理的に聞こえますが、私たちは同意しません。しかし、これを達成する方法を気にしないでください?何らかの理由で、多くの人は単に前提条件と事後条件に関する情報をスキップします。これは、何をする必要があるかを完全に説明しているだけです。
この記事では、すでに多くの材料が存在するこの原理の一般的な例については考慮しません(正方形と長方形またはサーモスタットコントロールの例)。ここでは、「前提条件」、「事後条件」などの概念についてもう少し詳しく説明し、共分散、反変性、不変性とは何か、および「歴史的制約」または「歴史のルール」とは何かを検討します。
サブクラスで前提条件を強化することはできません
️言い換えると、子クラスは、ビジネス動作を実行するために、基本クラスで定義されているよりも多くの前提条件を作成するべきではありません。次に例を示します。
<?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
. .
.
, , , , .
前後の状態を取り除くために努力することは言及する価値があります。理想的には、メソッドの入力/出力パラメーターとして定義する必要があります(たとえば、既製の値オブジェクトを署名に渡し、特定の有効なオブジェクトを出力に返すことによって)。
お役に立てば幸いです。