首先说说继承:
继承的优点:
1.代码共享
2.提高代码的重用性
4.提高代码的可重用性
5.提高代码的开放性
缺点:1.继承是带有侵入性的
2.降低了代码的灵活性
3.增强了耦合
什么是里氏替换?
简单说就是将父类出现的地方替换成子类,系统不会出现新的错误或异常。是实现抽象化的一种规范。
所有派生类的行为功能必须和使用基类的期望保持一致,避免出现派生类与基类不一致的行为
有名的两个悖论:正方形不是长方形和企鹅不是鸟;
这里简单说说企鹅不是鸟:
生物学中鸟是脊椎动物的一类,温血卵生,用肺呼吸,几乎全身有羽毛,后肢能行走,前肢变为翅,大多数能飞。鸟的主要特征是:身体呈流线型(纺锤型或梭形),大多数飞翔生活。体表被覆羽毛,一般前肢变成翼(有的种类翼退化);胸肌发达;直肠短,食量大消化快,即消化系统发达,有助于减轻体重,利于飞行;心脏有两心房和两心室,心搏次数快。体温恒定。呼吸器官除具肺外,还有由肺壁凸出而形成的气囊,用来帮助肺进行双重呼吸。
但这里我们来设计一个与鸟相关的程序:
所有的鸟都由鸟类派生:
鸟类:
public class Bird { //速度 private float veLocity; public virtual void Fly() { Console.WriteLine("I Can Fly !!!"); } public virtual void SetVeLocity(float v) { this.veLocity = v; } public double GetVeLocity() { return this.veLocity; } } //企鹅 public class Penguin:Bird { public override void Fly() { Console.WriteLine(" I Can't Fly ..."); } public override void SetVeLocity(float v) { //企鹅不会飞,所以速度为0 base.SetVeLocity(0); } } //测试类 class TestBird { public static void CalcTime(Bird bird) { float length = 10000; try { Console.Write("通过10000长的距离,耗时:"); Console.WriteLine(length / bird.GetVeLocity()); } catch (Exception ex) { Console.WriteLine(ex.Message); } } }
运行结果:
这里C#中虽然没有抛出异常,但从结果中我们看出再计算Penguin所用飞行时间时已经有了除0操作,这是不被允许的;已经和我们的期望相违背。
所以Penguin类和Bird类之间的继承关系违反了里氏代换原则,它们之间的继承关系不成立,企鹅不是鸟。
“企鹅到底是不是鸟”,企鹅是鸟也不是鸟,这个结论似乎就是个悖论。产生这种情况有两方面的原因:
-
没有搞清楚类的继承关系的定义
我们经常说类的继承关系就是一种“Is-A”关系,实际上指的是行为上的“Is-A”关系,
-
要看清程序依赖的具体环境
具体需求和环境而定,(如果要求根据是否是卵生来区分是否是鸟类,那企鹅就很明显符合要求了)
里氏替换原则实际上是给了我们一个类的继承原则:
如果不符合里氏替换原则则说明子类不应该继承该父类,需要考虑重新设计他们之间的关系。
(采用依赖、聚集组合等关系替换)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。