1.模式定义

  把会变化的内容取出并封装起来,以便以后可以轻易地改动或扩充部分,而不影响不需要变化的其他部分;

  2.问题缘起

  当涉及至代码维护时,为了复用目的而使用继承,结局并不完美。对父类的修改,会影响到子类型。在超类中增加的方法,会导致子类型有该方法,甚至连那些不该具备该方法的子类型也无法免除。示例,一个鸭子类型:

publicabstractclassDuck{
//所有的鸭子均会叫以及游泳,所以父类中处理这部分代码
publicvoidquack(){
System.out.println("Quack");
}

publicvoidswim(){
System.out.println("Allducksfloat,evendecoys.");
}

//因为每种鸭子的外观是不同的,所以父类中该方法是抽象的,由子类型自己完成。
publicabstractvoiddisplay();
}

publicclassMallardDuckextendsDuck{
//野鸭外观显示为绿头
publicvoiddisplay(){
System.out.println("Greenhead.");
}
}

publicclassRedHeadDuckextendsDuck{
//红头鸭显示为红头
publicvoiddisplay(){
System.out.println("Redhead.");
}
}

publicclassRubberDuckextendsDuck{
//橡皮鸭叫声为吱吱叫,所以重写父类以改写行为
publicvoidquack(){
System.out.println("Squeak");
}

//橡皮鸭显示为黄头
publicvoiddisplay(){
System.out.println("Yellowhead.");
}
}

  上述代码,初始实现得非常好。现在我们如果给Duck.java中加入fly()方法的话,那么在子类型中均有了该方法,于是我们看到了会飞的橡皮鸭子,你看过吗?当然,我们可以在子类中通过空实现重写该方法以解决该方法对于子类型的影响。但是父类中再增加其它的方法呢?

  通过继承在父类中提供行为,会导致以下缺点:

  a.代码在多个子类中重复;
  b.运行时的行为不容易改变;
  c.改变会牵一发动全身,造成部分子类型不想要的改变;

  好啦,还是刚才鸭子的例子,你也许想到使用接口,将飞的行为、叫的行为定义为接口,然后让Duck的各种子类型实现这些接口。这时侯代码类似于:

publicabstractclassDuck{
//将变化的行为fly()以及quake()从Duck类中分离出去定义形成接口,有需求的子类中自行去实现

publicvoidswim(){
System.out.println("Allducksfloat,evendecoys.");
}

publicabstractvoiddisplay();
}

//变化的fly()行为定义形成的接口
publicinterfaceFlyBehavior{
voidfly();
}

//变化的quack()行为定义形成的接口
publicinterfaceQuackBehavior{
voidquack();
}

//野鸭子会飞以及叫,所以实现接口FlyBehavior,QuackBehavior
publicclassMallardDuckextendsDuckimplementsFlyBehavior,QuackBehavior{
publicvoiddisplay(){
System.out.println("Greenhead.");
}

publicvoidfly(){
System.out.println("Fly.");
}

publicvoidquack(){
System.out.println("Quack.");
}
}

//红头鸭子会飞以及叫,所以也实现接口FlyBehavior,QuackBehavior
publicclassRedHeadDuckextendsDuckimplementsFlyBehavior,QuackBehavior{
publicvoiddisplay(){
System.out.println("Redhead.");
}

publicvoidfly(){
System.out.println("Fly.");
}

publicvoidquack(){
System.out.println("Quack.");
}
}