场景: 为了回家过年,我们都要先买火车票,然后坐火车,最后才能和家人团聚。
程序:
这里我们写个简单程序模拟回家过年。新建了一个NewYear类,它有一个celebrateSpringFestival()的方法,我们把买票,坐车,回家庆祝都写在这个方法。
public class NewYear { public void celebrateSpringFestival(){ //1.买票 System.out.println("买票"); //2.乘火车 System.out.println("乘火车"); //3.庆祝新年 System.out.println("新年快乐!"); } }
我们回家坐车,可以选择火车,汽车,飞机,因人而异。但不管坐哪种交通,都要先买票,再坐车,最后才回家过年。于是我们又新建一个类PassengerByCoach,由于买票和在家庆祝是一样的,只需要改乘坐交通方式的代码改而已。
代码如下:
public class PassengerByCoach{ public void celebrateSpringFestival(){ //1.买票 System.out.println("买票"); //2.乘汽车 System.out.println("乘汽车"); //3.庆祝新年 System.out.println("新年快乐!"); } }
如果我们要坐飞机,也是同样的代码,只改乘坐的交通方式的代码。随着交通工具的增多,以后要开发更多的类和测试类。这样,维护起来就麻烦了。为了解决重复代码出现,出现了模板模式的方法。
为了重复使用代码,我们使用继承机制。因为买票和在家庆祝两个功能是一样,所以抽出一个父类,把这些相同逻辑写在父类,因此有了buyTicket()和celebrate()两个方法。而乘坐交通方式写成travel()方法,让子类去实现各自不同的乘坐方式。并且在父类定义一个celebrateSpring()方法供客户端调用,实现买票,坐车,庆祝三个顺序的招待。
父类:
public abstract class HappyNewYear {
//1.买票,final不让子类个性其方法
protected final void buyTicket(){
System.out.println("买票");
};
//2.子类要实现的具体乘坐方式
protected abstract void travel();
//3.庆祝
protected final void celebrate(){
System.out.println("新年快乐!");
};
public void celebrateSpring(){
buyTicket();
travel();
celebrate();
}
}
现在编写子类,实现一个乘坐飞机的子类。
public class PassengerbyAir extends HappyNewYear { @Override protected void travel() { System.out.println("坐飞机"); } }
同样,可以再写乘坐汽车,乘坐火车的两个子类。
public class PassengerbyCoach extends HappyNewYear { @Override protected void travel() { System.out.println("坐汽车"); } } public class PassengerbyTrain extends HappyNewYear { @Override protected void travel() { System.out.println("坐火车"); } }
结果:
...CiCi准备回家...
买票
坐飞机
新年快乐!
...GiGi准备回家
买票
坐汽车
新年快乐!
...MiMI准备回家
买票
坐火车
新年快乐!
总结:
使用继承,子类中不需要实现那些重复买票和庆祝过年的代码,只需要实现不同的回家方式代码,避免了代码的重复。父类中的celebrate()方法是一个模板方法(也叫框架方法),它把回家过年分为三步,其中方法travle是抽象方法,用于子类实现不同的逻辑,所以我们使用的是模板模式方法。
模板模式有如下功能:
1.能够解决代码冗余问题。在例子中,PassengerbyAir ,PassengerbyCoach ,PassengerbyTrain 没有必要再去实现buyTickey()和celebrate()方法了。
2.易于扩展。我们通过创建新类,实现可定制化的方法就可以扩展功能。如果有人坐船回家,加入PassengerByBoat类并实现travel()方法即可。
3. 父类提供了算法的框架,控制方法执行流程,而子类不能改变算法流程,子类方法调用由父类模板方法决定。
4.父灰可以把那些重要的不允许改变的方法屏蔽掉,不让子类去重写。我们可以声明这些为private 或final.