一、继承(继承强调的是is-a的关系)
一、继承的优点
1)Java语言不支持类的多重继承,也就是说,一个子类做多只能有一个父类 。如果要想实现多重继承,只能通过接口的多重继承来实现。
2)子类只能继承父类的非私有(public、protected)的成员变量和方法。
3)当子类中定义的成员变量与父类中的成员变量重名时,子类中的成员变量会覆盖父类中的成员变量,而不是继承父类中的成员变量。
4)当子类中的方法签名与父类中的方法签名相同(重名)时(前提是个数相同、方法类型相同),子类会覆盖父类中的方法,也不会继承。
二、继承的缺点
(1) 继承破坏封装性
给父类增加了一个方法A,这时子类与父类之间就可能越来越脱离is-a
举个例子:比如,鸟类有羽毛等属性,这里有一个需求是,定义一个有羽毛的鸡类,采用继承的方法很优雅也很方便,直接一个extends 就可以实现,但是如果有一天,这个鸟类添加了一个飞翔的公有方法,此前继承了鸟类的鸡类会自动继承了这个方法,鸡会飞翔?顶多就是矮距离飞跃。此时给鸡飞的方法就是破坏了鸡的封装性,鸡不应该有此方法。此时的鸡已经和有飞翔行为的鸟类之间不是is-a 关系了。
(2) 继承是紧耦合:
继承紧耦合体现在父类变就会影响子类,此时子类如果因此需要修改,重构的难度可能会很高。
(3) 子类对父类的扩展往往会增加系统结构复杂度
继承树深度加深,结构越复杂。
(4) 不支持在运行时指定父类
(5) 子类不能改变父类的接口
二、组合(组合强调的是has-a的关系。)
一、什么是组合
组合是一种较弱的关系,是has-a的关系,给个代码:
1 public class Animal { 2 private void beat(){ 3 System.out.println("心脏跳动..."); 4 } 5 public void breath(){ 6 beat(); 7 System.out.println("呼吸中..."); 8 }
1 public class Bird { 2 //将Animal作为Bird的成员变量 3 private Animal a; 4 public Bird(Animal a){ 5 this.a = a; 6 } 7 public void breath(){ 8 a.breath(); 9 } 10 public void fly(){ 11 System.out.println("我在飞.."); 12 } 13 14 public static void main(String[] args){ 15 Animal animal = new Animal(); 16 Bird b = new Bird(animal); 17 b.breath(); 18 b.fly(); 19 } 20 }
二、组合的优点
- 组合不破坏封装,相对于继承
- 组合松耦合,包装类和被包装类彼此独立,不会因为被包装类突然加个方法就使得包装类多了一个方法,包装类视情况包装所需方法。
- 支持动态组合,组合的方式在运行时可以根据条件来选择所组合的类。
- 包装类可以通过包装改变被包装类的接口,比如被包装类是实现了Set接口的,我可以通过包装,让包装类实现Map接口。
三、组合的缺点
- 不能实现多态
- 无法自动获得被包装类的接口,比如被包装类实现了Set接口,包装类并没有自动获得此接口,需要经过包装,才有可能和他一样的接口。
三、什么情况下使用继承,什么情况下使用组合
- 1.如果两个类的关系不是“is-a”的关系,最好就不要用继承;不要为了减少代码或者提高代码的复用性而使用继承,而导致后期代码结构被破坏,造成代码的 可维护性差。一旦父类被修改,就会影响到其继承的子类,从而增加维护难度和成本(需求老是改的话,牵一发而动全身)。
- 2.不要因为实现多态而使用继承,如果class之间没有extends的关系,就可以通过接口与组合的方式来达到相同的目的。设计模式中的策略模式就是对这一点很好的体现,采用接口与组合的方式比采用继承的方式有更好的可拓展性。
- 一切都是为了提高代码的复用性(代码重构的原因),避免代码的臃肿,造成后期可维护性变差造成的成本增加。