模板方法模式是我工作中用到最多的模式,这个模式的类图比较简单,而且思路也比较简单,只要有重复的工作,加以抽象,都可以使用模板方法。
模板方法的前提道理很好讲,但是很多人依旧会问,为什么他的编码环境却没有这样的使用情况。
设计模式是基于面向对象的套路,所以脱离不了抽象这个概念,很多情况之所以没办法去模式化主要是因为无法抽象。
我们做一件事情,都是分步骤的,例如去煮咖啡,先准备咖啡,然后水加热,放咖啡豆,结束后装入容器。针对这件事情,并不能有什么想法,抽象的基础是找共同点,起码是两个事物之间的影响的结果,如果还有一件事情是煮茶叶,那么过程就是准备茶叶,然后水加热,放茶叶,结束后装入容器。那么明显可以抽象煮东西的这个过程。准备材料,水加热,放材料,结束后装入容器。但是另外一件事情是砍柴,那么这样貌似就不好找细节上的共同点了。很多情况下,没有模式主要是场景的问题,编码就写一个场景,共同点不好找,纯粹靠想象去抽象,可能模式是用上了,但是没有普及性。效果基本和没有模式差不多。
类图模板方法模式的主要的思想就是定制一个流程,每个实现类都去遵循这个流程。这个流程是需要通过具体场景去抽象的。
常见案例最开始学习web编程的时候都会接触HttpServlet,写自己的servlet的时候,要继承这个类,去重写doget和dopost。这里用的就是模板方法模式。具体的流程就在service方法中。
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
//get
if (method.equals("GET"))
{
long lastModified = getLastModified(req);
if (lastModified == -1L)
{
doGet(req, resp);
}
else
{
long ifModifiedSince;
try
{
ifModifiedSince = req.getDateHeader("If-Modified-Since");
}
catch (IllegalArgumentException iae)
{
long ifModifiedSince;
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L)
{
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
}
else
{
resp.setStatus(304);
}
}
}
//head
else if (method.equals("HEAD"))
{
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
}
//post
else if (method.equals("POST"))
{
doPost(req, resp);
}
//put
else if (method.equals("PUT"))
{
doPut(req, resp);
}
//delete
else if (method.equals("DELETE"))
{
doDelete(req, resp);
}
//options
else if (method.equals("OPTIONS"))
{
doOptions(req, resp);
}
//trace
else if (method.equals("TRACE"))
{
doTrace(req, resp);
}
else
{
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
在service中对http支持的7中方式都做了处理,剩下的就是每个servlet根据自己的情况覆写doGet,doHead,doPost,doPut,doDelete,doOptions,doTrace。具体的业务也写在具体的方法里,具体是调用的是哪种请求方法由service方法中确认。
思想类似的产物java的jdbc的操作都是获取连接,创建statment或者preparestatement,然后执行sql,然后关闭resultset(如果有的话),关闭statement,然后关闭连接。具体和业务相关的其实就是sql,剩下的都是流程化的过程。spring jdbc template就是模板化了这些过程,不同的是,他使用了组合的方式去调用而不是继承,严格意义上不是标准的模板方法,只能说是思想类似。
实战场景工作中遇到一个场景就是用模板方法来做一个try catch的异常模板。
场景最开始写的代码出现一个问题,就是有异常没有处理的话,逻辑都被中断了。因此需要加入异常处理。要这样改的地方还有很多。
代码模板
public class Template {
public static void main(String[] args) {
new ExceptionTemplate(){
@Override
protected void toDo() {
//流程
System.out.println("over");
}
}.doWork();
}
}
//模板类
abstract class ExceptionTemplate{
public final void doWork(){
try{
toDo();
}catch(Exception e){
//异常处理方式
}
}
protected void toDo(){}
}
好处
每个地方的改动都是有限的,都是new一个匿名内部类,调用一下方法,原来的写的代码都移动到抽象类方法中,提交的代码的变动相对比较少,而且不容易出错,逻辑都在模板里,只要想好一个就可以了。