里氏代换原则
1、继承的优缺点
继承的优点:
- 子类拥有父类的所有方法和属性,从而可以减少创建类的工
作量。 - 提高了代码的重用性。 提高了代码的扩展性,子类不但拥有了父类的所有功能,还可以添加自己的功能。
继承的缺点:
- 继承是侵入性的。只要继承,就必须拥有父类的所有属性和
方法。 - 降低了代码的灵活性。因为继承时,父类会对子类有一种约
束。 - 增强了耦合性。当需要对父类的代码进行修改时,必须考虑
到对子类产生的影响。有时修改了一点点代码都有可能需要
对大段程序进行重构。
2、读程序,解决问题
public class Liskov {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a = new A();
System.out.println("11-3=" +a.func1(11,3));
System.out.println("1-8="+a.func1(1,8));
System.out.println ("-------");
B b = new B();
System.out.println("11-3=" + b.func1(11,3));//这里本意是求出11-3
System.out.println("1-8="+ b.func1(1,8));//这里本意是求出1-8
System.out.println("11+3+9="+b.func2(11,3));
}
}
class A{
public int func1(int num1, int num2){
return num1-num2; }
}
class B extends A{
public int func1(int a,int b){
return a+b;}
public int func2(int a, int b){
return func1(a,b)+9;}
}
这边要重点思考B继承A中的func1以及新方法func2
输出结果为,显然与我们预想的不一样
分析:
原来运行正常的相减功能发生了错误。原因就是类B重写了父类的方func1,造成原有功能出现错误。 在实际编程中,常常会通过重写父类的方法完成新的功能,
这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候。
修改后
public class Liskov {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a = new A();
System.out.println("11-3=" +a.func1(11,3));
System.out.println("1-8="+a.func1(1,8));
System.out.println ("-------");
B b= new B();
//因为B类不再继承A类,因此调用者,不会再认为func1是求减法
//调用完成的功能就会很明确
System. out.println("11+3=" + b. func1(11, 3));//这里本意是求出11+3
System. out.println("1+8=" + b.func1(1, 8));// 1+8
System. out.println("11+3+9=" + b.func2(11, 3));
//使用组合仍然可以使用到A类相关方法
System. out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3
}
}
//创建-个更加基础的基类
class Base {
//把更加基础的方法和成员写到Base类
}
//A类
class A extends Base {
//返回两个数的差
public int func1(int num1, int num2) {
return num1 - num2; }
}
class B extends Base{
A a=new A();
public int func1(int a,int b){
return a+b; }
public int func2(int a, int b){
return func1(a,b)+9; }
public int func3(int a, int b){
return this.a.func1(a,b); }
}
现在的输出结果为
- 只要有父类出现的地方,都可以使用子类来替代。而且不会出现任何错误或者异常。但是反过来却不行。子类出现的地方,不能使用父类来替代。
- 里氏代换原则的主要作用:规范继承时子类的一些书写规则。其主要目的就是保持父类方法不被覆盖。
通用的解决思路:
让原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替。
最后里氏代换原则规定,子类不能覆写父类已实现的方法。父类中已实现的方法其实是一种已定好的规范和契约,如果随意修改它,那么可能会带来意想不到的错误。