对于继承的思考:
①继承包含这样一层含义:凡是在父类中已经存在方法,实际上是在设定规范和契约,虽然他不强制所有的子类都必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承系统造成破坏
②继承在给程序设计带来便利的同时也点来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象之间的耦合性,如果一个类被其他类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改以后,所涉及的子类的功能也有可能产生故障
③解决方案:里式替换原则
在使用继承的是时候,尽量遵循里式替换原则,即尽量不要去重写父类中的方法。里式替换原则告诉我们:继承实际上让两个类耦合性增强了,在适当的情况下,可以通过耦合、组合、依赖来解决问题
所有引用基类的地方必须能透明的使用其子类的对象,尽量不要改写父类的方法
先看一段代码
1 public class Liskov { 2 3 public static void main(String[] args) { 4 // TODO Auto-generated method stub 5 A a = new A(); 6 System.out.println("11-3=" + a.func1(11, 3)); 7 System.out.println("1-8=" + a.func1(1, 8)); 8 9 System.out.println("-----------------------"); 10 B b = new B(); 11 System.out.println("11-3=" + b.func1(11, 3));//这里本意是求出11-3 12 System.out.println("1-8=" + b.func1(1, 8));// 1-8 13 System.out.println("11+3+9=" + b.func2(11, 3)); 14 } 15 16 } 17 18 // A类 19 class A { 20 // 返回两个数的差 21 public int func1(int num1, int num2) { 22 return num1 - num2; 23 } 24 } 25 26 // B类继承了A;增加了一个新功能:完成两个数相加,然后和9求和 27 class B extends A { 28 //注意这里B类重写了A类中的func1方法,之前是求差,现在是求和了。这样必然会出现问题 29 public int func1(int a, int b) { 30 return a + b; 31 } 32 33 public int func2(int a, int b) { 34 return func1(a, b) + 9; 35 } 36 }
代码解读:调用者实际是想求两个数之差,结果方法被子类重写,变成了求和。这样固然导致程序结果和期望是不一样的
通常的做法是让原来的父类和自己继承一个更加的一般的类(基类),是之前的继承关系变成组合、耦合或者是依赖关系
看一下改进的代码
1 public class Liskov { 2 3 public static void main(String[] args) { 4 // TODO Auto-generated method stub 5 A a = new A(); 6 System.out.println("11-3=" + a.func1(11, 3)); 7 System.out.println("1-8=" + a.func1(1, 8)); 8 9 System.out.println("-----------------------"); 10 B b = new B(); 11 //因为B类不再继承A类,因此调用者,不会再func1是求减法 12 //调用完成的功能就会很明确 13 System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11+3 14 System.out.println("1+8=" + b.func1(1, 8));// 1+8 15 System.out.println("11+3+9=" + b.func2(11, 3)); 16 17 18 //使用组合仍然可以使用到A类相关方法 19 System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3 20 21 22 } 23 24 } 25 26 //创建一个更加基础的基类 27 class Base { 28 //把更加基础的方法和成员写到Base类 29 } 30 31 // A类 32 class A extends Base { 33 // 返回两个数的差 34 public int func1(int num1, int num2) { 35 return num1 - num2; 36 } 37 } 38 39 // B类继承了A 40 // 增加了一个新功能:完成两个数相加,然后和9求和 41 class B extends Base { 42 //如果B需要使用A类的方法,使用组合关系 43 private A a = new A(); 44 45 46 public int func1(int a, int b) { 47 return a + b; 48 } 49 50 public int func2(int a, int b) { 51 return func1(a, b) + 9; 52 } 53 54 //我们仍然想使用A的方法 55 public int func3(int a, int b) { 56 return this.a.func1(a, b); 57 } 58 }
很显然这个时候A和B之间关系有之前的继承变成了组合关系。也就是说各自的功能互不影响;且降低类与类之间的耦合度