概念
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模板方法模式类图:
例子
大家可能还记得2000年赵本山跟宋丹丹小品的笑话吧,“把大象装冰箱总共分三步,把冰箱门打开、把大象装进去、把冰箱门关上”。那么这个过程用代码描述如下:
public class PutElephantInsideFridge{
public void openDoor(){
Sysrtem.out.println("打开冰箱门");
}
public void putElephant(){
Sysrtem.out.println("把大象装进冰箱");
}
public void closeDoor(){
Sysrtem.out.println("关闭冰箱门");
}
public void put(){
this.openDoor();
this.putElephant();
this.closeDoor();
}
}
但是如果我想把狮子装进冰箱,代码该怎么描述呢?显然,除了第二步,其他都一样。那么面对第一、第二步冗余的代码可以将其抽象到父类中,第二步过程由子类去实现。put
方法用final
关键字修饰,避免子类破坏了算法流程。
public abstract class PutSomethingInsideFridge{
public void openDoor(){
Sysrtem.out.println("打开冰箱门");
}
public abstract void putSomething();
public void closeDoor(){
Sysrtem.out.println("关闭冰箱门");
}
public void put(){
this.openDoor();
this.putElephant();
this.closeDoor();
}
}
public class PutElephant extends PutSomethingInsideFridge{
@Override
public void putSomething(){
System.out.println("将大象装进冰箱");
}
}
这就是一个简单的模板方法模式,这样改写之后,以后再想把狮子、河马放进冰箱也只需要多写几个类而不必重复整个算法流程。
钩子函数
有用过React、Vue或者小程序开发经验的小伙伴应该对coponentDidMount
、onLoad
等等生命周期函数不陌生,这些函数就是所谓的钩子函数。而钩子函数就是通过模板方法模式实现的。
还是以上面的例子为例,假如我想在打开冰箱门之前再做点别的事,那么就可以这样做:
public abstract class PutSomethingInsideFridge{
public void openDoor(){
Sysrtem.out.println("打开冰箱门");
}
public abstract void putSomething();
public void closeDoor(){
Sysrtem.out.println("关闭冰箱门");
}
public void beforeOpenDoor(){
}
public void put(){
this.beforeOpenDoor();
this.openDoor();
this.putElephant();
this.closeDoor();
}
}
public class PutElephant extends PutSomethingInsideFridge{
@Override
public void putSomething(){
System.out.println("将大象装进冰箱");
}
@Override
public void beforeOpenDoor(){
System.out.println("打开冰箱门之前");
}
}
总结
模板方法模式就是将子类中不变的部分抽象到父类,可变的部分由子类去实现。
优点
模板方法模式是将子类中不变的部分抽象到父类,可变的部分由子类去实现。
缺点
每新增一个不同的实现都需要增加一个子类,可能导致类数量变多,增加系统复杂性