在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。换句话说:抽象父类定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
在上例子之前,先说一下:模板模式中的方法分为两大类:模版方法和基本方法,而基本方法又分为:抽象方法,具体方法,钩子方法。
用煎牛排和煎鸡蛋来举例说明:
1.煎牛排:
public class FriedSteak {
/**
* @Description: 煎牛排方法
* @Author: yyf
* @Date: 2021/7/21
*/
void cook(){
prepareBeef();
fried();
eat();
prepareWine();
}
private void prepareBeef() {
System.out.println("准备牛肉");
}
private void fried() {
System.out.println("油煎");
}
private void eat() {
System.out.println("开吃");
}
private void prepareWine() {
System.out.println("再配瓶红酒~");
}
public static void main(String[] args) {
FriedSteak FriedSteak = new FriedSteak();
FriedSteak.cook();
}
}
执行结果:
2.煎鸡蛋:
public class FriedEggs {
/**
* @Description: 煎鸡蛋方法
* @Author: yyf
* @Date: 2021/7/21
*/
void cook(){
prepareEggs();
fried();
eat();
}
private void prepareEggs() {
System.out.println("准备鸡蛋");
}
private void fried() {
System.out.println("油煎");
}
private void eat() {
System.out.println("开吃");
}
public static void main(String[] args) {
FriedEggs friedEggs = new FriedEggs();
friedEggs.cook();
}
}
执行结果:
对比煎牛排和煎鸡蛋,我们发现其中准备食材的方法是类似的,油煎和开吃的方法是固定不变的,准备红酒是煎牛排特有的(现实也可以煎鸡蛋配红酒~)。为了减少代码的冗余,这个时候就可以使用模版模式来定义好煎制食物的骨架方法,看代码:
建一个煎制食物的抽象父类:
/**
* @Description: 煎制食物抽象类
* @Author: yyf
* @Date: 2021/7/21
*/
public abstract class FriedFood {
//cook方法就是前文说的模版方法,也是煎制食品的骨架,final修饰
final void cook(){
prepareFood();
fried();
eat();
if(needWine()){
System.out.println("再配瓶红酒~");
}
}
//准备食材作为基本方法里的抽象方法,供子类实现
protected abstract void prepareFood();
//油煎和开吃是基本方法里的具体方法,不可覆盖
private void fried() {
System.out.println("油煎");
}
private void eat() {
System.out.println("开吃");
}
//是否需要红酒是基本方法里的钩子方法,返回一个空实现,子类可以选择是否覆盖
boolean needWine() {
return false;
}
public static void main(String[] args) {
FriedFood friedEggs = new FriedEggsNew();
friedEggs.cook();
System.out.println("-------------------");
FriedFood friedSteak = new FriedSteakNew();
friedSteak.cook();
}
}
子类煎鸡蛋继承煎制食物父类并覆盖父类的prepareFood()抽象方法
public class FriedEggsNew extends FriedFood{
//这里必须覆盖父类FriedFood的准备食材抽象方法
@Override
protected void prepareFood() {
System.out.println("准备鸡蛋");
}
}
子类煎牛排继承煎制食物父类并覆盖父类的prepareFood()抽象方法,并且覆盖父类的needWine()钩子方法
public class FriedSteakNew extends FriedFood{
//这里必须覆盖父类FriedFood的准备食材抽象方法
@Override
protected void prepareFood() {
System.out.println("准备牛肉");
}
//煎牛排时想配红酒喝,所以选择覆盖父类的needWine方法
@Override
boolean needWine(){
return true;
}
}
来看执行结果:
总结:
抽象父类定义一个操作中的算法的骨架,子类在不改变一个算法的结构即可重定义该算法的某些特定步骤。这种设计模式就是模板模式。