第三只眼看:里氏替换原则
面试的时候经常会被问到一个弱智题:面向对象的三个基本特征是什么?
这时候你完全可以以请教的口气优雅的反问一道题,看看ta对"继承"的理解(不过这驳考官面子的后果可得想清楚哦!):
class Father
{
public virtual void fun()
{
Console.WriteLine("你好!");
}
}
class Son : Father
{
public override void fun()
{
Console.WriteLine("Hello !");
}
}
上面两个类是继承关系吗?谈谈你对继承的理解,并用面向对象的思想改写代码。
好了,先卖个关子不说答案是,先来看看什么是里氏替换原则。
里氏替换原则
定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都换成o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。
通俗的定义:所有引用基类的地方必须能透明地使用其子类的对象雅思答案
按照我的理解就是:父亲能干是事情,儿子都能干;父亲干不了的,儿子也能干;所有父亲要干的事情,都可以让儿子去干。
(所以对于上面的问题,我的回答是:这算不上继承,因为父亲说的是汉语,但是儿子只会说英语,我们是心中有对象的人,这违背了里氏替换原则,应该将子类的override换乘new)
第三只眼:
再来看看一个关于 人(Person)和女人(Woman)的关系。
abstract class Person
{
//也可以不加virtual,但无virtual的情况下派生类能可以被覆盖,但不可以被重写。
//更多virtual和override的区别略…
public virtual void DoSomething()
{
Console.WriteLine("制造劳动工具 !"); //这是人和动物的基本区别
}
}
//***************************************************************************
class Woman : Person
{
override public void DoSomething()
{
Console.WriteLine("生小孩 !");
}
}
//***************************************************************************
class Program
{
static void Main(string[] args)
{
Person p = new Woman(); //用子类去替换父类
p.DoSomething();
Woman w = new Woman();
w.DoSomething();
Console.ReadKey();
}
}
运行结果:(人) 生小孩!
(女人)生小孩!
不是人人都能生小孩的,用子类替换父类后,这明显违背了常理,这也违背了里氏替换原则的"子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法"的思想。
这时候我们可以用new去隐藏父类的方法,让person继续干person的事,把生小孩的事情留给woman:托福答案
class Woman : Person
{
new public void DoSomething() //或public new void DoSomething()
{
Console.WriteLine("生小孩 !");
}
}
在思考一个关于女孩与女人的问题:
按照常规思维,女孩属于女人,所以女孩继承自女人。
接着上面…
class Girl:Woman
{
public void Sing()
{
Console.WriteLine("唱歌");
}
}
女孩对女人这个类进行了扩展,但是问题就出来了,这时候女孩就有了生小孩的能力,如果女人再有个大姨妈,难道女孩也要继承?
这时如果让女人继承自女孩好像更妥,女孩可以唱歌,而女人可以唱歌、生小孩、来个例假什么的…
虽然这没有违背面向对象继承的任何原则,但却不适合用常规思维去定义面向对象的类。
总结:被override重写的类最好是sealed类,即该类不能再派生子类 www.yzyxedu.com
不要用感性的常规思维去理解面向对象的继承,对于类的定义与继承一定要准确且不违背常理。