1. 杂言:
设计模式,现在觉得每种模式像工业行业的一些典型零件。这些零件也可以变种出很多类似零件。吧这些零件组合起来,就成了一台机器。好吧,我现在是这么理解的。
一般代码结构都是,一层调用一层,就是一般都是顶层的调用底层的。但模板方法确实反过来的,有父类调用子类的方法。这个听说又牵扯到啥好莱坞原则。对于这种理论的了解多看就懂了,其实相对于其他模式,这个模板方法可能以前代码页经常用到。也就是不经意间可能就会用到了。不过深入学习下可能对以后的使用会更加严谨和灵活。
2. 理论:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
3. UML图:
我画的图
4. 举例:
今天我比较严肃,所以举个正常点的例子。比如我们平时要做菜,做菜其实就是材料加做法,然后就完成了一道美味的加油。我现在用代码实现一个番茄炒蛋的制作过程,来说明下这个模板方法模式。
a. 遇到问题
说到做菜,那问题来了。山东蓝翔。。。哦不,用代码实现一个番茄炒蛋的过程简单。但要做其他菜肴呢。现在写代码都讲究通用是不?所以我想写出个通用的模板来实现各种菜的制作过程。这时,就可以用上今天的主题了——模板方法设计模式。
b.代码实现
定义模板抽象类
package prov.sue.design.template;
public abstract class AbstractDishes {
public void makeDishes()
{
putMaterial();
whithMethod();
}
public abstract void putMaterial();
public abstract void whithMethod();
}
然后实现番茄炒蛋细节部分。
package prov.sue.design.template;
public class FQCDDishes extends AbstractDishes{
@Override
public void putMaterial() {
// TODO Auto-generated method stub
System.out.println("放蛋,放番茄");
}
@Override
public void whithMethod() {
// TODO Auto-generated method stub
System.out.println("炒");
}
}
应用
package prov.sue.design;
import prov.sue.design.template.AbstractDishes;
import prov.sue.design.template.FQCDDishes;
public class DesignMain {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractDishes dishes = new FQCDDishes();
dishes.makeDishes();
}
}
c. 结果
输出
放蛋,放番茄
炒
5. 应用实例:
下面是百度出来的应用实例
模板方法模式在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()。