模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
模板模式的关键是:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑,每当定义一个新的子类时,不要按照控制流程的思路去想,而应当按照“责任”的思路去想。换言之,应当考虑哪些操作是必须置换掉的,哪些操作是可以置换掉的,以及哪些操作是不可以置换掉的。使用模板模式可以使这些责任变得清晰,下面给出一个追求女孩的模板。
Coding:
1、模板类
/**
* Java设计模式之模板模式
*
* 吖大哥提供了一个文明而向上的追女孩的步骤,具体怎么追怎么才能成功就看你们自己了,健康有效的模板如下
*
* @author 吖大哥
* @date Jun 3, 2014 9:25:42 AM
*/
public abstract class AbstractTemplet {
/** 巧遇 */
public abstract void across();
/** 约会 */
public abstract void appointment();
/** 表白 */
public void express() {
System.out.println("喜欢你");
}
/** 追求 */
public abstract boolean pursuit();
/** 接吻 */
public abstract boolean kissing();
/** 上床 */
public void sleep() {
boolean flag1 = pursuit();
boolean flag2 = kissing();
// 吖大哥建议两步成功之后可以考虑上床
if (flag1 && flag2) {
System.out.println("你可以和她上床了…………………………………………");
} else if (!flag2 || !flag1) {
System.out.println("你追求或者接吻失败啦,你们不能上床…………………………………………");
}
}
/** 追女孩 */
public final void chasingGirls() {// 使用final关键字锁定子类只能按如下步骤来追女孩
across();
appointment();
express();
sleep();
}
}
2、浪漫的追求者类
/**
* 浪漫温馨的追求者
*
* @author 吖大哥
* @date Jun 3, 2014 10:08:18 AM
*/
public class RomanticGetGirl extends AbstractTemplet {
@Override
public void across() {
System.out.println("无意间的邂逅");
}
@Override
public void appointment() {
System.out.println("浪漫的约会");
}
@Override
public boolean kissing() {
System.out.println("深情的接吻");
return true;
}
@Override
public boolean pursuit() {
System.out.println("缠绵的追求");
return true;
}
}
3、狂野的追求者类
/**
* 狂野的追求者
*
* @author 吖大哥
* @date Jun 3, 2014 10:08:42 AM
*/
public class CrazyGetGirlImpl extends AbstractTemplet {
@Override
public void across() {
System.out.println("疯狂的偶遇");
}
/** 表白 */
public void express() {
System.out.println("我他妈的贱B嗖嗖的喜欢上你了");
}
@Override
public void appointment() {
System.out.println("疯狂的找人家约会");
}
@Override
public boolean kissing() {
return false;
}
@Override
public boolean pursuit() {
return false;
}
public void sleep() {
System.out.println("咱们直接上床吧………………………………");
}
}
4、客户端测试
public class Client{
public static void main(String[] args) {
AbstractTemplet at1 = new RomanticGetGirl();
at1.chasingGirls();
System.out.println("================================");
AbstractTemplet at2 = new CrazyGetGirlImpl();
at2.chasingGirls();
}
}
5、测试结果:
无意间的邂逅
浪漫的约会
喜欢你
缠绵的追求
深情的接吻
你可以和她上床了…………………………………………
================================
疯狂的偶遇
疯狂的找人家约会
我他妈的贱B嗖嗖的喜欢上你了
咱们直接上床吧………………………………
模板方法模式在Servlet中的应用
使用过Servlet的人都清楚,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供,因此这是典型的模板方法模式。下面是service()方法的源代码
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); } }
当然,这个service()方法也可以被子类置换掉。
下面给出一个简单的Servlet例子:
从上面的类图可以看出,TestServlet类是HttpServlet类的子类,并且置换掉了父类的两个方法:doGet()和doPost()。
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"); } }
从上面的例子可以看出这是一个典型的模板方法模式。
HttpServlet担任抽象模板角色
模板方法:由service()方法担任。
基本方法:由doPost()、doGet()等方法担任。
TestServlet担任具体模板角色
TestServlet置换掉了父类HttpServlet中七个基本方法中的其中两个,分别是doGet()和doPost()。