里氏替换原则是Barbara Liskov女士在1998年发表的ASD,具体的数学定义比较复杂,你可以查相关资料。它的白话翻译------》就是一个软件实体如果使用的是一个父类的话,那么一定要适用于子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化(其实,就是多态)。
里氏替换原则(LSP):子类型必须能够替换他们的父类型。
---里氏替换原则,使得开放-封闭原则成为了可能。对类本身修改关闭,对子类,派生类扩展开放!!!(当然依赖倒置原则也可以,它们是用接口实现。)
---一个应用实例:
只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正的被复用,而子类也能够在父类的基础上增加新的行为。(比方说,猫是继承动物类的,以动物身份拥有吃eat,喝drink,跑run,叫shout等行为,可当某一天,我们需要狗,牛,羊也拥有类似的行为,由于他们都是继承于动物,所以除了更改实例化的地方,程序其他处不需要改变。)
public class Animal //对修改关闭,对扩展开放
{
public virtual void eat(){}
public virtual void drink(){}
public virtual void run(){}
public virtual void shout(){}
}
public class Dog:Animal //扩展类,对扩展开放,本身不用改变
{
public override void shout()
{
Console.WriteLine("我是狗") ;
}
}
public class Cat:Animal
{
public override void shout()
{
Console.WriteLine("我是猫") ;
}
}
//...,一堆扩展类
public class Program //对修改关闭
{
public Animal a1;
public Program(Animal animal)
{
if(animal!=null)
{
this.a1=animal;
}
}
public void shout()
{
if(a1!=null)
{
a1.shout();
}
else
{
Console.WriteLine("传入对象为空!");
}
}
}
---下边是控制台主程序中,调用实例代码(需要更改的地方):
Animal dog=new Dog();
Animal cat=new Cat();
Program p=new Program(cat);
p.shout(); //输出,我是猫,如果想输出,我是狗,上边传入实例化对象dog,就可以了。
Console.ReadKey();
@总结:
1,看上去很不可思议,因为我们会发现在自己编程中常常会违反里氏替换原则,程序照样跑的好好的。所以大家都会产生这样的疑问,假如我非要不遵循里氏替换原则会有什么后果?
后果就是:你写的代码出问题的几率将会大大增加。
2,按LSP原则,则要注意:若子类不能完整地实现父类的方法(例如鸟类会飞,企鹅类继承了鸟类,但企鹅不会飞,这就是不能完整地实现父类的方法,所以企鹅类不能继承鸟类。),或者父类的某些方法在子类中发生畸变,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。
3,采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类也可以继续运行。在实际项目中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑。(多态!!!)
4,联系依赖倒置原则记忆!