02-里氏替换原则(LSP)

1. 背景

       有一个功能p1,由类A完成,现在需要将功能p1进行扩展,扩展后的功能为p3,p3由原功能p1和新功能p2组成,而新功能p3和p2均由类A的子类B来完成,子类B在完成新功能p2的同时,可能会导致原有的功能p1故障。

2. 定义

    所有引用基类的地方能透明的使用其子类对象进行替代。

3. 对应的解决方案

  使用继承时,父类已经实现好了的方法(非抽象方法),实际上是有一系列规范和契约的,虽然不强制子类必须遵循,但如果子类对这些非抽象方法进行重写、重载后,会造成整个继承体系被破坏。而里氏替换原则也正是表达了这层含义。

4. 补充对继承的理解

   继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。

5.  案例

    需求一:完成两个数相减的功能,由类A完成。

 1  public class A
 2     {
 3         /// <summary>
 4         /// 两数相加
 5         /// </summary>
 6         /// <param name="a"></param>
 7         /// <param name="b"></param>
 8         /// <returns></returns>
 9         public int func1(int a, int b)
10         {
11             return a - b;
12         }
13         /// <summary>
14         /// 两数相乘
15         /// </summary>
16         /// <param name="a"></param>
17         /// <param name="b"></param>
18         /// <returns></returns>
19         public int func3(int a, int b)
20         {
21             return a * b;
22         }
23     }

    需求二:完成两个数相加,然后再加100的功能,由类A的子类类B完成。

 1   public class B:A
 2     {
 3         public int func1(int a, int b)
 4         {
 5             return a + b;
 6         }
 7         public int func2(int a, int b)
 8         {
 9             return func1(a, b) + 100;
10         }
11     }

 下面我们对上述写的代码进行测试。

    (1). 用类A测试两个数相减,如:100-50

    (2). 用类B测试两个数相减(因为类B继承了类A),如:100-50

    (3). 用类B测试两个数相加后再加100的功能,如:100+50+100

 1         public static void show()
 2         {
 3             //需求1:完成两个数相减的功能,由类A来完成
 4             A a = new A();
 5             Console.WriteLine("100-50={0}", a.func1(100, 50));   //50
 6 
 7             //需求2:完成两个数相加功能,然后再加100,由类A的子类B来完成
 8             B b = new B();
 9             Console.WriteLine("100-50={0}", b.func1(100, 50));   //150,因为子类重写了fun1,则隐藏了父类中fun1原有的方法 (错误)
10             Console.WriteLine("100和50相加,然后再减掉100,结果为:{0}", b.func2(100, 50));   //250
11 
12         }

 结果:

  

   我们会发现, 用类B测试两个数相减的功能出错了,竟然变成两数相加的功能了,原因是类B中声明了和其父类相同的方法名的方法,即隐藏了父类原有的方法,违背了里氏替换原则。

6. 里氏替换原则的深刻理解

 

 子类可以扩展父类没有的功能,但是不能改变父类的功能

a:子类可以实现父类的抽象方法,但不能重写父类的非抽象方法。

b:子类可以增加自己特有的方法。

c:子类重载父类方法时,其方法的形参要比父类方法的形参更宽松。

d:子类实现父类抽象方法时,其方法的返回值要比父类方法的更严格。

 

7. 正宗的里氏替换原则的用法

 

        public static void show()
        {

            A aa = new B();
            Console.WriteLine("100*50={0}",aa.func3(100, 50));   //5000   正宗的里氏替换原则
            //Console.WriteLine(aa.func2(100, 50));   //代码报错,父类不能调用子类扩展的方法
        }

 

8. 违背里氏替换原则的后果

 

 出错率会增高

 

转载于:https://www.cnblogs.com/yaopengfei/p/7101345.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值