模板方法模式(Template Method)
我曾在一本书上看过作者将模板比喻成带有镂空文字的薄薄的塑料版。只要用笔在模板的镂空处就可以临摹出整齐的图案。我们可以通过塑料版上镂空的洞就可以知道是什么文字图案,但是文字图案具体是什么颜色的,效果如何,就只能依赖于使用什么样的笔去临摹了。但是文字图案的形状一定是和镂空的图案一致的。
模板方法是一种行为设计模式。通过定义一个抽象类作为父类,然后声明一些抽象方法和一个具体的模板方法,模板方法定义了操作调用的框架,即具体调用哪些方法以及调用顺序。而方法的具体实现则交给子类,不同的子类就会有不同的实现效果,这也是模板方法设计模式的目的所在。
模板方法的角色
- 抽象模板(AbstractClass)
抽象模板类AbstractClass负责定义模板方法需要的抽象方法和实现具体的模板方法,模板方法定义了对抽象方法的逻辑调用顺序。
- 具体模板(ConcreateClass)
具体模板类继承抽象模板,负责实现抽象类中定义的抽象方法。
实践模板方法
假设我们需要在一个运动场举行各种各样的体育赛事,每场比赛赛事都包含了运动员进场握手、比赛中、运动员退场、清理场地这样的步骤。这些步骤会因为具体赛事的不同会有不同的表现,我们就可以将赛事举办过程抽象成为一个抽象类(即抽象模板)。
/**
* @Descrtption Game 一场比赛
* @Author luke
* @Date 2019/11/20
**/
public abstract class Game {
/**模板方法,需要加上final关键字*/
public final void play(){
handshake();
fight();
exit();
clean();
}
/**运动员握手*/
protected abstract void handshake();
/**双方交战中*/
protected abstract void fight();
/**双方运动员退场*/
protected abstract void exit();
/**打扫场地*/
private final void clean(){
System.out.println("观众退场,打扫场地");
}
}
定义了抽象模板Game之后,我们就可以定义具体的赛事了,那就来一场拳击比赛和一场足球比赛吧。这些具体的比赛赛事需要继承抽象的赛事模板。
/**
* @Descrtption BoxingGame 拳击比赛
* @Author luke
* @Date 2019/11/20
**/
public class BoxingGame extends Game{
@Override
protected void handshake() {
System.out.println("用拳套触碰");
}
@Override
protected void fight() {
System.out.println("你一拳呀我一拳");
}
@Override
protected void exit() {
System.out.println("运动员送往医疗室理疗");
}
}
/**
* @Descrtption FootballGame 足球比赛
* @Author luke
* @Date 2019/11/20
**/
public class FootballGame extends Game{
@Override
protected void handshake() {
System.out.println("两队球员依次握手");
}
@Override
protected void fight() {
System.out.println("你一脚呀我一脚");
}
@Override
protected void exit() {
System.out.println("队伍绕场一周致谢观众,里皮愤怒立场");
}
}
定义完抽象模板Game和具体的实现模板BoxingGame、FootballGame之后,我们就可以来模拟举办这两场比赛了。
/**
* @Descrtption Main
* @Author luke
* @Date 2019/11/20
**/
public class Main {
public static void main(String[] args) {
//来一场真男人的比赛
Game game = new BoxingGame();
game.play();
System.out.println("--------------------");
//来一场男足比赛
game = new FootballGame();
game.play();
}
}
用拳套触碰
你一拳呀我一拳
运动员送往医疗室理疗
观众退场,打扫场地
--------------------
两队球员依次握手
你一脚呀我一脚
队伍绕场一周致谢观众,里皮愤怒立场
观众退场,打扫场地
设计模式延伸-抽象类
在学习设计模式过程中,我们会经常的使用到抽象类和接口,对于抽象类我们是无法实例化的,例如对于Game这个抽象类,它只是定义一次抽象比赛的赛事,无法指定具体是什么比赛。抽象类能够去定义处理的流程,将具体的实现由子类去控制,可以达到封装和解耦的效果,让我们的代码更具扩展性。设计模式能够帮助我们当新的需求来临的时候,代码不需要做太大的修改,不会让我们的代码变得臃肿,难以维护。
假设我们现在需要举办一场篮球比赛,我们只需要增加一个具体模板类BasketballGame即可,客户端不需要做任何改变,因为客户端依赖的是Game这个抽象类,而不是具体实现类,这就是抽象类或者说设计模式的意义,这种变与不变就是设计模式中的开闭原则,对扩展开放,对修改关闭。
使用场景
通过上面的介绍你也许已经知道了在哪些场景可以使用模板方法,能够将多个子类的方法抽象成共有方法,并且会有逻辑相同的执行过程,并且这个过程是一个复杂、重要的方法,那么就可以考虑使用模板方法。同时因为抽象模板定义了固定的执行过程,所以一般情况下需要将模板方法定义为final类型。
模式比较
在前面文章介绍的工厂方法的时候,我们定义了抽象工厂CarFactory。因为建造车的过程是比较复杂的,无法通过一个简单的new来构造出car对象,而这个负责的建造的过程又是一个具有固定步骤的过程,设计、购买材料、加工生产。你会惊讶发现这不就是模板方法吗?没错,这里的建造过程正是使用到了模板方法设计模式。随着读者不断实践模板方法你会发现,工厂方法往往会结合模板方法一块使用。同时我们也需要区分他们之间的使用差异,工厂方法注重于怎么构建出对象,而模板方法则注重于某个具有固定步骤的过程。
public abstract class CarFactory {
public final Car createCar(){
Car car = design();//设计
buyMaterial(car);//购买材料
working(car);//加工生产
return car;
}
protected abstract Car design();
protected abstract void buyMaterial(Car car);
protected abstract void working(Car car);
}
java中使用到模板方法
1、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
2、HttpServlet类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供,因此这是典型的模板方法模式。
共同学习,写下你的评论
评论加载中...
作者其他优质文章