里斯科夫替换
或如何创建漂亮的缩写
这是有关SOLID原则的第三篇文章-如果您错过了开放封闭原则 ,请查看。 在这里,我首先简要介绍一下此概念的形成方式,并演示一个描述性示例(我保证,不包括Square和Rectangle!)。
伯特兰·迈耶 ( Bertrand Meyer) ,1986年
伯特兰·迈耶(Bertrand Meyer)首先介绍了合同的概念,并以他的埃菲尔语言将其实现。 合同由前提条件 , 不变 条件和后置条件确定 。 这是维基百科的一个不错的总结:
1. [例程可以]期望任何调用它的客户端模块在输入时都会保证一定的条件:例程的前提条件-对客户端的义务,以及对供应商的好处(例程本身),因为它释放了它不必在前提条件之外处理案件。
2.保证在退出时拥有一定的财产:例程的后置条件—供应商的义务,显然是客户的利益(调用例程的主要利益)。
3.维护一个确定的属性,该属性假定是在进入时假定的并且在退出时保证的: class invariant 。
我只知道一种语言,合同是一种内在的概念-它是Eiffel本身。 在其他语言中,合同可以通过方法的签名来强制执行:参数的类型,返回值的类型以及可以引发的异常。 但是由于发明一种可以用来执行所有现有业务规则的类型系统几乎是不可行的,因此这种方法非常有限。
芭芭拉·里斯科夫 (1994)
芭芭拉·李斯科夫(Barbara Liskov)提出其原则的方式代表了子类型化或亚型多态性的概念。 这种类型的多态性在面向对象的编程中最常见,通常简称为“多态性”。 Liskov正式采用了迈耶的方法,并且在学术上看起来更像是:
令φ(x)是关于类型T的对象x的一个可证明性质。那么,对于类型S的对象y,其中S是T的子类型,则φ(y)应该为true。
易于阅读的版本几乎重复了Bertrand Meyer已经说过的所有内容,但完全依赖于类型系统:
1.前提条件不能在子类型中得到加强。
2.子条件不能弱化后置条件。
3.超类型的不变量必须保留在子类型中。
罗伯特·马丁 (1996)
罗伯特·马丁(Robert Martin)使定义听起来更加流畅和简洁:
使用对基类的引用的指针的函数必须能够在不知道的情况下使用派生类的对象。
但是,他没有引入任何新内容。
违反利斯科夫换人原则
我经常发现,为了理解某些原则,重要的是要意识到何时被违反。 那就是我现在想做的。
违反这一原则意味着什么? 这意味着一个对象不满足由接口表示的抽象所施加的约束。 换句话说,这意味着您标识了错误的抽象 。
考虑以下示例:
interface Account
{
/**
* Withdraw $money amount from this account.
*
* @param Money $money
* @return mixed
*/
public function withdraw(Money $money);
}
class DefaultAccount implements Account
{
private $balance ;
public function withdraw(Money $money)
{
if (!$this->enoughMoney($money)) {
return ;
}
$this-> balance ->subtract($money);
}
}
这是否违反LSP? 是的,因为Account的合同告知您将提取一个帐户,但这并非总是如此。 那我该怎么做才能解决它? 我只是修改合同:
interface Account
{
/**
* Withdraw $money amount from this account if its balance is enough.
* Otherwise do nothing.
*
* @param Money $money
* @return mixed
*/
public function withdraw(Money $money);
}
Voilà,现在合同已履行。
这种细微的冲突常常使客户有能力分辨所采用的具体对象之间的差异。 例如,给定第一个帐户的合同,它可能如下所示:
class Client
{
public function go(Account $account, Money $money)
{
if ($account instanceof DefaultAccount && !$account->hasEnoughMoney($money)) {
return ;
}
$account->withdraw($money);
}
}
这自动违反了开放封闭原则 。
这一点也解决了我经常遇到的违反LSP的错误观念。 就像“如果父母的行为改变了孩子,则违反了LSP”。 只要孩子没有违反父母的合同,它就不会。
SOLID中的Liskov替代原理
我用这个缩写词的问题是,如果那里存在“多态性”,为什么没有“封装”和“可组合性”呢? 这些绝不重要。 可能是因为很难用“ e”和“ c”提出漂亮的缩写吗? 我敢打赌。
结语
不要误会我的意思,我喜欢SOLID及其提倡的方法。 但这只是其深层原则的基础。 上面的示例清楚地说明了该原理的作用: 松散耦合 。 换句话说,不要让您的客户关心所使用的具体类。 崇高的目标,但如何实现呢? 首先,首先分解问题空间 -域。 其次,在方法签名中用简明的英语表达您的合同。
翻译自: https://hackernoon.com/liskov-substitution-principle-a982551d584a
里斯科夫替换