里氏代换原则的概念
里氏代换原则官方的解释是说:任何基类可以出现的地方,子类一定可以出现
大白话说就是:子类可以扩展父类的功能,但是不能改变父类原有的功能
再通俗点说就是:子类继承父类时,除添加新的方法完成新的功能以外,尽量不要重写父类的方法
为什么里氏代换原则要求继承父类时不要重写的方法?
继承作为面向对象的三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承时会给程序带来侵入性,程序的可移植性降低了,增加了对象间的耦合性,比如一个类被其他的类继承了,则当这个类要修改时,,就必须要考虑所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。
举个栗子
A类有个方法操作两个数
public class ClassA {
public int function1(int a, int b) {
return a - b;
}
}
B类继承了A类,重写了A类的function1方法,并有自己的方法
这里还是JDK自带提示,实现父类方法必须要加上@Override注解,如果没有这个注解就更难发现了
public class ClassB extends ClassA {
@Override
public int function1(int a, int b) {
return a + b;
}
public int function2(int a, int b) {
return a * b;
}
}
此时的B类重写了A类的方法,并且修改了方法原有的逻辑,实现了自己的逻辑
做个测试,简单模拟一下出错场景
public class Test {
public static void cal(ClassA classA) {
System.out.println("100-50 = " + classA.function1(100, 50));
}
public static void main(String[] args) {
ClassA classA = new ClassA();
cal(classA);
ClassB classB = new ClassB();
cal(classB);
}
}
我们会看到得到的结果完全是不一样的,当然实际的场景当然没这么简单,但由于这样的一个错误而导致的后果往往都是致命的,在庞大的项目调用链中,你需要一直往上点,然后分析代码原有逻辑和出错逻辑,最后解决了问题,但是同时也浪费了大量的时间
下面的例子就是里氏代换原则建议的方式
public class ClassB extends ClassA {
public int function2(int a, int b) {
return a * b;
}
public int function3(int a, int b) {
return a + b;
}
}
public class Test {
public static void cal(ClassA classA) {
System.out.println("100-50 = " + classA.function1(100, 50));
}
public static void main(String[] args) {
ClassA classA = new ClassA();
cal(classA);
ClassB classB = new ClassB();
cal(classB);
}
}
在不干扰父类原有逻辑的情况下,添加自己的方法,这样在调用的时候也能使用父类的方法,减少了有可能发生的错误