继承与组合
继承的弊端
继承是实现类复用的重要手段 但继承带来了一个最大的坏处 破坏封装 相比之下 组合也是实现类复用的重要方法 采用组合方式 来实现类复用能提供更好的封装性
public class Person { private String name; public Person(){ run(); } public void eat(){ System.out.println("eat 东西"); } public void run(){ eat(); } }
public class Teacher extends Person{ private String name; @Override public void run() { System.out.println("子类重写父类方法" + name.length()); } }
public static void main(String[] args) { Teacher teacher = new Teacher(); teacher.run(); }
当系统创建Teacher对象时 会先执行父类构造器 父类会调用run()方法 此时调用的是子类重写的run方法 此时name没有赋值为空 所以报空指针异常
何时使用继承?
1.子类需要额外增加属性 而不仅仅是属性值的改变 例如从Person类派生出Student子类 Persion类没有提供grade属性
而Student类需要grade属性来保存Student对象就读的年纪 这种父类到子类的派生 符合java继承前提
2.子类需要增加自己独有的行为 例如从persion类派生出Teacher类 其中Teacher类需要增加一个teaching方法用于描述Teacher对象独有的行为方式 教学
利用组合实现复用
public class Person { private String name; public Person(){ run(); } public void eat(){ System.out.println("eat 东西"); } public void run(){ eat(); } }
public class Teacher extends Person{ private String name; @Override public void run() { } }
public class WoMan extends Person{ @Override public void run() { } }
通过让Teacher和WoMan继承Persion 从而复用Person提供的run方法 从不敢软件复用的角度来看 将上面三个类定义改为如下形式也可以实现相同复用
public class Teacher{ // 将父类组合到子类 作为子类组合的一部分 private Person person; public Teacher(Person person){ this.person = person; } // 重新定义一个自己的run方法 public void run(){ person.run(); } }
public class WoMan{ private Person person; public WoMan(Person person){ this.person = person; } public void run(){ person.run(); } }
到底用继承 还是用组合 ? 继承是对已有的类做一番改造 以此获得一个特殊的版本 对于上面的woman和teacher 继承更能表达其实现意义 如果2个类直接有明确的整体 部分 关系 例如person类复用Arm类的方法(Persion对象由Arm对象组合而成)此时就应该采用组合关系来实现复用 把Arm作为Persion类组合成员变量 总之继承要表达是一种"is-a“关系 组合表示的是 "has-a”的关系