好了好了言归正传,开始我们的正文。本日由“菜鸟”为大家分享一下设计模式七大原则中的“里氏更换原则”。讲该原则之前我们不得不提一下面向工具工具的三大特性,它们分别是:封装、继续、多态。相信理解面向工具编程的程序员,对这三大特性肯定不会陌生。
那么肯定就有人会产生疑问了,这三大特性跟我们本日的内容有什么关系吗?别慌且听“菜鸟”逐步诉说,我们本日禀享的“里氏更换原则”便是专门为“继续”所准备的。
我们该当都知道利用继续也是存在弊端的,它会给程序带来侵入性,并且降落程序的可移植性,还会增加工具之间的耦合性。当父类须要修正时,须要考虑到所有的子类,盲目修正父类,有可能会造成子类的功能产生非常。

为了减少这些弊端,就产生了“里氏更换原则”,该原则是1988年由麻省理工一位名为Barbara Liskov的女士提出。通过其名称,我们该当能看出来该原则的重点就在“更换”这两个字上。
该原则的核心思想便是在程序当中,如果将一个父类工具更换成它的子类工具后,该程序不会发生非常。这也是该原则希望达到的一种空想状态。
下面就让我们从四个方面来深入理解一下里氏更换原则。
第一点讲第一点之前我们先思考在“继续”中会面临的这样一个问题:我们的父类定义好的方法,并不会逼迫哀求其子类必须完备遵守该方法的实现规则,它是可以修正继续自父类的任意方法的。
如以下代码所示:
public class Demo { public static void main(String[] args) { Superclass superclass = new Superclass(); superclass.add(3, 2); Son son = new Son(); son.add(3, 2); }}/ 父类 /class Superclass { public void add(int num1, int num2) { int value = num1 + num2; System.out.println("父类打算出的结果为:" + value); }}/ 子类 /class Son extends Superclass { @Override public void add(int num1, int num2) { int value = num1 - num2; System.out.println("子类打算出的结果为:" + value); }}
父类的本意是想要定义一个两数相加的方法,但是子类继续该方法后却修正为减法,并且也成功了。这样操作后,会对全体继续体系造成毁坏。当你想把利用父类的地方更换为其子类时,会创造原来的正常的功能现在涌现问题了。
为理解决此问题,就有了里氏更换原则的第一点:
子类可以实现父类中的抽象方法,但是不能重写(覆盖)父类的非抽象方法。
如果我们严格遵守该原则就不会产生上面的问题。
第二点当我们迫不得已须要在子类中添加一个跟父类方法名称相同的方法时,就须要遵守下面这点。
当子类须要重载父类中的方法的时候,子类方法的形参(入参)要比父类方法输入的参数更宽松(范围更广)。。
这句话的意思大家能明白吗?不是特殊清楚也不用焦急,请看下面的代码。
/ 父类 /public class Superclass { public void method(ArrayList arrayList) { System.out.println("父类方法实行了!
"); }}/ 子类 /public class Son extends Superclass { // 重载了父类的method,并且方法入参比父类的入参范围更广。 public void method(List list) { System.out.println("子类方法实行了!
"); }}
那么这样做有什么意义那,目的又是为了什么那?大家可以先思考一下。
实在很大略,这样做最直接的一个目的便是防止我们将父类工具更换为子类工具后,造成方法调用混乱的问题。
请看下面测试代码和其实行结果:
public static void main(String[] args) { ArrayList list = new ArrayList(); Superclass superclass = new Superclass(); Son son = new Son(); System.out.print("利用父类工具调用的结果:"); superclass.method(list); System.out.print("将父类工具更换成子类工具后的调用结果:"); son.method(list); }
实行结果如下:
如果没有遵守上面的规则的话就会造成很大的麻烦,请看下列示例代码。
public class Demo2 { public static void main(String[] args) { ArrayList list = new ArrayList(); Superclass superclass = new Superclass(); Son son = new Son(); System.out.print("利用父类工具调用的结果:"); superclass.method(list); System.out.print("将父类工具更换成子类工具后的调用结果:"); son.method(list); }}/ 父类 /class Superclass { public void method(List arrayList) { System.out.println("父类方法实行了!
"); }}/ 子类 /class Son extends Superclass { public void method(ArrayList list) { System.out.println("子类方法实行了!
"); }}
测试结果如下:
确实发生问题了吧!
我们的本意是希望工具更换后还实行原来的方法的,可结果却发生变革了。这样是不符合里氏更换原则的。以是我们要时候牢记,子类方法的入参要比父类的入参范围更大,这样才不会造成不必要的缺点。
当我们须要重写或者实现父类方法时,须要遵守下面这一点。
重写或者实现父类方法的时候,方法的返回值可以被缩小,但是不能放大。
示例代码:
/ 父类 /public class Superclass { public List getList() { return new ArrayList(); }}/ 子类 /public class Son extends Superclass { @Override public ArrayList getList() { return new ArrayList(); }}
如果我们试图在子类中放大,重写或实现来自父类方法的返回值时,代码会报错,连基本的编译器都无法通过。
第四点子类可以拥有自己独特的方法或属性。
这句话就更好理解了,它解释子类不只可以拥有从父类继续来的东西,也可以进行自我扩展,编写属于自己的东西。
这一点相信大家都明白,我就不在编写示例代码了。
总结通过上面的描述相信大家都对里氏更换原则有了一个基本的观点,实在它便是见告我们在继续中须要把稳什么问题和遵守什么规则。
然而在实际开拓中我们在很多时候还是会违背该原则的,虽然表面上没有什么特殊大的问题,但是这样做会大大增加代码的出错率。我们编写代码时不只要考虑怎么实现该功能,程序的健壮性和后期的扩展以及移植都是须要考虑到的。只有这样做才可以使我们的程序更加精良。
好了本日的分享就到这里了,如果觉得“菜鸟”的文章写的还不错的,记得点赞加关注呦!
你们的支持便是我坚持下去的动力。