模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
模板模式的关键是:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑,每当定义一个新的子类时,不要按照控制流程的思路去想,而应当按照“责任”的思路去想。换言之,应当考虑哪些操作是必须置换掉的,哪些操作是可以置换掉的,以及哪些操作是不可以置换掉的。使用模板模式可以使这些责任变得清晰,下面给出一个追求女孩的模板。
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()。