继承和组合的特点和区别
类继承和对象组合是代码复用的两种最常用的技术
一、继承
继承是 Is-a 的关系,比如说Student继承Person,则说明Student is a Person。继承的优点是子类可以重写父类的方法来方便地实现对父类的扩展。
继承的优点有:
1、容易进行新的实现,因为其大多数可继承而来;
2、 易于修改或扩展那些被复用的实现;
继承的缺点有:
1、父类的内部细节对子类是可见的;
2、子类从父类继承的方法在编译时就确定下来了,所以无法在运行期间改变从父类继承的方法的行为;
3、如果对父类的方法做了修改的话(比如增加了一个参数),则子类的方法必须做出相应的修改。所以说子类与父类是一种高耦合,违背了面向对象思想。
二、组合
组合是 has-a 的关系,组合就是设计类的时候把要组合的类的对象加入到该类中作为自己的成员变量。
组合的优点:
1、当前对象只能通过所包含的那个对象去调用其方法,所以所包含的对象的内部细节对当前对象时不可见的;
2、当前对象与包含的对象是一个低耦合关系,如果修改包含对象的类中代码不需要修改当前对象类的代码;
3、当前对象可以在运行时动态的绑定所包含的对象。可以通过set方法给所包含对象赋值。
组合的缺点:
1、容易产生过多的对象;
2、为了能组合多个对象,必须仔细对接口进行定义。
由此可见,组合比继承更具灵活性和稳定性,所以在设计的时候优先使用组合。只有当下列条件满足时才考虑使用继承:
1、子类是一种特殊的类型(String类、Object类、包装类),而不只是父类的一个角色;
2、子类的实例不需要变成另一个类的对象;
3、子类是父类的扩展,而不是覆盖或者使父类的功能失效;
为什么使用组合关系?
类继承允许我们根据自己的实现来覆盖重写父类的实现细节,父类的实现对于子类是可见的,我们一般称之为白盒复用。对象持有(其实就是组合)要求建立一个号的接口,但是整体类和部分类之间不会去关心各自的实现细节,即它们之间的实现细节是不可见的,故成为黑盒复用。
继承是在编译时刻静态定义的,即是静态复用,在编译后子类和父类的关系就已经确定了。而组合这是运用于复杂的设计,它们之间的关系是在运行时候才确定的,即在对对象没有创建运行前,整体类是不会知道自己将持有特定接口下的那个实现类。在扩展方面组合比集成更具有广泛性。
继承中父类定义了子类的部分实现,而子类中又会重写这些实现,修改父类的实现,在设计模式中认为这是一种破坏了父类的封装性的表现。这个结构导致的结果是父类实现的任何变化,必然导致子类的改变。然而组合这不会出现这种现象。对象的组合就是有助于保持每个类被封装,并被集中在单个任务上(符合类设计的单一原则)。这样类的层次结构不会扩大,一般不会出现不可控的庞然大类。而类的继承就可能出来这些问题,所以一般编码规范都要求类的层次结构不要超过3层。组合是大型系统软件实现即插即用时的首选方式。
最后还有一点,“优先使用对象组合,而不是继承”是面向对象设计的第二原则。但并不是说什么都设计都用组合,只是优先考虑组合,更不是说继承即使不好的设计,应该用组合,应为他们之间也有各自的优势。