组合和继承,都是在新类中直接复用旧类的方法,实现系统功能重用。但是各有不同的特点。继承会破坏封装。组合能提供更好的封装性。各有优缺点,总得来说,多用组合,少用继承。
继承:
子类扩展父类,继承父类的字段和方法,如果访问权限允许,子类可以直接访问父类的字段和方法,很方便,但也破坏了父类的封装性。每个类都应该封装内部信息和实现,只暴漏必要的方法给其他类使用。但继承子类可以直接访问父类内部信息。
保证父类良好封装性的设计原则
1.尽量隐藏父类内部数据
2.不要让子类可以随意访问,修改父类方法
Private:子类无法访问
Protected:非子类不能自由访问
Final:子类不能重写
3.尽量不要在父类的构造器中调用将要被子类重写的方法
何时从父类派生新的子类:
1.子类需要额外增加属性,而不仅仅是属性值的改变。
2.子类需要增加自己独特的行为方式。
继承是在编译时刻静态定义的,即是静态复用
组合:
该类当成另一个类的组合成分,允许新类直接复用该类的Public方法。
组合把旧类对象作为新类的Field嵌入,实现新类的功能,用户看到的是新类的方法。新类中使用private修饰嵌入的旧类对象。
组合是在运行时才确定的,增加了程序的灵活性。
用EA生成的代码框架
public class Animal {
public Animal(){}
private void beat(){}
public void breath(){}
}
public class Bird
{
<strong>public Animal m_Animal;</strong>
public Bird(){}
public void breath(){}
public void fly(){}
}
public class Wolf
{
<strong>public Animal m_Animal;</strong>
public Wolf(){}
public void breath(){}
public void run(){}
}
完善代码:
class Animal
{
private void beat()
{
System.out.println("心脏跳动。。。");
}
public void breath()
{
beat();
System.out.println("吸一口气,吐一口气,呼吸中");
}
}
class Bird
{
//原来父类嵌入子类,作为子类的组合成分;
private Animal a;
public Bird(Animal a)
{
this.a=a;
}
//定义自己的breath方法;
public void breath()
{
//直接复用父类的Breath来实现子类的Breath;
a.breath();
}
public void fly()
{
System.out.println("我在天空自在的飞翔");
}
}
class Wolf
{
//原来父类嵌入子类,作为子类的组合成分;
private Animal a;
public Wolf(Animal a)
{
this.a=a;
}
//定义自己的breath方法;
public void breath()
{
//直接复用父类的Breath来实现子类的Breath;
a.breath();
}
public void run()
{
System.out.println("我在陆地上快速奔跑");
}
}
public class CompositeTest {
public static void main(String[] args)
{
//显示创建嵌入的对象
Animal a1 = new Animal ();
Bird b = new Bird(a1);
b.breath();
b.fly();
//显示创建嵌入的对象
Animal a2 = new Animal();
Wolf w = new Wolf(a2);
w.breath();
w.run();
}
}
运行结果:
总结:
多用组合,少用继承。组合将对象作为新类的Field,运行时创建对象,增加程序的灵活性,但是整体类创建时,需要创建所有的局部对象。继承让子类很便捷的拥有父类的信息,破坏了父类的封装性。组合和继承各有优缺点,在实际开发中应落实实际情况,发展的眼光,选择相对合适的。