继承属于OO三大特性之一,往往其提供的复用性让人称道,但是它也带来了严重的问题:继承严重地破坏了父类的封装性。在继承关系中,子类可以直接访问父类中的Field和方法,从而造成子类和父类的严重耦合。并且,子类在继承中拥有的重写更是加重了继承的危害:重写父类已有方法,将子类实例赋给父类引用,编译时是父类,而真正运行时却成了子类。这就是偷天换日,如:
Animal a = new Bird();
a.breath();
这种情况有可能被别人利用。
这是我们需要考虑使用另外一种复用的方法:组合模式。组合模式的方法是用一个class成为另一个class的一部分来实现复用的。
首先我们先看看继承的实现:
package test.testinherite;
//定义一个刺客的类
class Cike
{
public void tujin()
{
System.out.println("刺客一般都有突进技能");
}
public void shouge()
{
System.out.println("刺客一般都能够收割人头");
}
}
class AKL extends Cike
{
public void fangwu()
{
System.out.println("AKL有保护技能——放雾");
}
}
class Kate extends Cike
{
public void tiao()
{
System.out.println("卡特只能跳来跳去");
}
}
public class InheritTest {
public static void main(String[] args)
{
AKL akl = new AKL();
akl.tujin();
akl.shouge();
akl.fangwu();
Kate kate = new Kate();
kate.tujin();
kate.shouge();
kate.tiao();
}
}
接下来看看组合:
package test.testforcomposite;
//定义一个刺客的类
class Cike{
public void tujin()
{
System.out.println("刺客一般都有突进技能");
}
public void shouge()
{
System.out.println("刺客一般都能够收割人头");
}
}
class AKL{
private Cike cike = new Cike();
public AKL(Cike cike)
{
this.cike = cike;
}
public void tujin()
{
cike.tujin();
}
public void shouge()
{
cike.shouge();
}
public void fangwu()
{
System.out.println("AKL有保护技能——放雾");
}
}
class Kate{
private Cike cike = new Cike();
public Kate(Cike cike)
{
this.cike = cike;
}
public void tujin()
{
cike.tujin();
}
public void shouge()
{
cike.shouge();
}
public void tiao()
{
System.out.println("卡特只能跳来跳去");
}
}
public class CompositeTest {
public static void main(String[] args)
{
Cike cike = new Cike();
AKL akl = new AKL(cike);
akl.tujin();
akl.shouge();
akl.fangwu();
Kate kate = new Kate(cike);
kate.tujin();
kate.shouge();
kate.tiao();
}
}
我们可以看到两者实现的效果是一样的。组合中利用AKL和Kate的构造器引入Cike,并在其方法中完成复用Cike的方法。
总结一下:
继承要表达的是一种“是(is a)”关系,而组合表达的是“有(has a)”的关系。