模板方法是基于继承复用的基本技术。模板方法通过一个抽象类,定义了一些抽象方法,迫使子类实现。抽象类还以具体实现的方式提供了一致性的对外接口,实现对公共逻辑方法的组装。

其中AbstractTemplate中的handle方式为具体方法,prepare,doSomething和finish方法为抽象方法。ConcreteClass实现了所有的抽象方法。

1
2
3
4
5
public void handle(){
prepare();
doSomething();
finish();
}

组成

  1. 模板方法

    一个模板方法定义在抽象类中,把基本操作方法组合在一起形成一个总算法或总行为的方法。一个抽象类可以有任意多个模板方法,而不限于一个,每一个模板方法都可以调用任意多个具体方法。

  2. 基本方法

    基本方法可以分为三种,抽象方法,具体方法和钩子方法

    • 抽象方法

      一个抽象方法由抽象类声明,具体子类实现

    • 具体方法

      一个具体方法由抽象类声明并实现,子类不实现或重写

    • 钩子方法

      一个钩子方法由抽象类声明并实现,子类可以进行扩展

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* 模板类
**/
public abstract class Account {
/**
* 模板方法,计算利息数额
* @return 返回利息数额
*/
public final double calculateInterest(){
double interestRate = doCalculateInterestRate();
String accountType = doCalculateAccountType();
double amount = calculateAmount(accountType);
return amount * interestRate;
}
/**
* 基本方法留给子类实现
*/
protected abstract String doCalculateAccountType();
/**
* 基本方法留给子类实现
*/
protected abstract double doCalculateInterestRate();
/**
* 基本方法,已经实现
*/
private double calculateAmount(String accountType){
/**
* 省略相关的业务逻辑
*/
return 7243.00;
}
}
/**
* 具体实现类
**/
public class MoneyMarketAccount extends Account {

@Override
protected String doCalculateAccountType() {

return "Money Market";
}

@Override
protected double doCalculateInterestRate() {

return 0.045;
}

}

public class CDAccount extends Account {

@Override
protected String doCalculateAccountType() {
return "Certificate of Deposite";
}

@Override
protected double doCalculateInterestRate() {
return 0.06;
}

}

//客户端
public class Client {

public static void main(String[] args) {
Account account = new MoneyMarketAccount();
System.out.println("货币市场账号的利息数额为:" + account.calculateInterest());
account = new CDAccount();
System.out.println("定期账号的利息数额为:" + account.calculateInterest());
}
}

模板方法在Servlet中的应用

Servlet继承自一个叫做HttpServlet的抽象类。HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成客户端调用响应。这些do方法需要由HttpServlet的具体子类提供,这就是典型的模板方法。

  • HttpServlet担任模板角色,service()提供模板方法,doPost()和doGet()等提供基本方法
  • TestServlet担任模板角色,重写了父类的do方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

String method = req.getMethod();

if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}

} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);

} else if (method.equals(METHOD_POST)) {
doPost(req, resp);

} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);

} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);

} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);

} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);

} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//

String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);

resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}

//子类继承自模板类,并具体实现do方法
public class TestServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

System.out.println("using the GET method");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

System.out.println("using the POST method");
}

}