微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

6大设计原则之里氏替换原则

首先说说继承:

    继承的优点:

        1.代码共享

        2.提高代码的重用性

        3.子类可以形似父类但又异于父类

        4.提高代码的可重用性

        5.提高代码的开放性

    缺点:1.继承是带有侵入性的

          2.降低了代码的灵活性

          3.增强了耦合

什么是里氏替换?

    简单说就是将父类出现的地方替换成子类,系统不会出现新的错误或异常。是实现抽象化的一种规范。


  1. 尽量不要重写父类已实现的方法

  2. 尽量不要重载父类方法;当子类重载父类方法时,方法的入参要比父类的入参更加宽松

  3. 所有派生类的行为功能必须和使用基类的期望保持一致,避免出现派生类与基类不一致的行为

  4. 子类完全实现父类方法,当子类实现父类的抽象方法时,返回值要比父类的返回值更加严格



有名的两个悖论:正方形不是长方形和企鹅不是鸟;



这里简单说说企鹅不是鸟:

生物学中鸟是脊椎动物的一类,温血卵生,用肺呼吸,几乎全身有羽毛,后肢能行走,前肢变为翅,大多数能飞。鸟的主要特征是:身体呈流线型(纺锤型或梭形),大多数飞翔生活。体表被覆羽毛,一般前肢变成翼(有的种类翼退化);胸肌发达;直肠短,食量大消化快,即消化系统发达,有助于减轻体重,利于飞行;心脏有两心房和两心室,心搏次数快。体温恒定。呼吸器官除具肺外,还有由肺壁凸出而形成的气囊,用来帮助肺进行双重呼吸。

但这里我们来设计一个与鸟相关的程序:

所有的鸟都由鸟类派生:

鸟类:

  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);
            }
        }
    }


运行结果:

wKiom1OElXKg9KTVAABYXKCTUz4223.jpg

这里C#中虽然没有抛出异常,但从结果中我们看出再计算Penguin所用飞行时间时已经有了除0操作,这是不被允许的;已经和我们的期望相违背。

所以Penguin类和Bird类之间的继承关系违反了里氏代换原则,它们之间的继承关系不成立,企鹅不是鸟。


“企鹅到底是不是鸟”,企鹅是鸟也不是鸟,这个结论似乎就是个悖论。产生这种情况有两方面的原因:

  1. 没有搞清楚类的继承关系的定义

    我们经常说类的继承关系就是一种“Is-A”关系,实际上指的是行为上的“Is-A”关系,

    也就是说是关注的对象的行为,这里是使用行为来对对象进行分类的,只有行为一致才能抽象出一个类来

  2. 要看清程序依赖的具体环境

    具体需求和环境而定,(如果要求根据是否是卵生来区分是否是鸟类,那企鹅就很明显符合要求了)

里氏替换原则实际上是给了我们一个类的继承原则:

如果不符合里氏替换原则则说明子类不应该继承该父类,需要考虑重新设计他们之间的关系。

(采用依赖、聚集组合等关系替换)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐