Java模板方法模式

模板方法模式


  在一个算法中定义了一个算法骨架,而将一些算法延迟到子类中。模板方法使得子类可以再不改变算法结构的情况下,重新定义算法中的某些步骤。

算法中的钩子(hook):

钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,是子类能够针对算法的不同点进行挂钩。要不要挂钩,由子类自行决定。

默认钩子方法

  一个钩子方法常常由抽象类给出一个空实现作为此方法的默认实现。这种空的钩子方法叫做“Do Nothing Hook”。显然,这种默认钩子方法在缺省适配模式里面已经见过了,一个缺省适配模式讲的是一个类为一个接口提供一个默认的空实现,从而使得缺省适配类的子类不必像实现接口那样必须给出所有方法的实现,因为通常一个具体类并不需要所有的方法。

命名规则

  命名规则是设计师之间赖以沟通的管道之一,使用恰当的命名规则可以帮助不同设计师之间的沟通。

  钩子方法的名字应当以do开始,这是熟悉设计模式的Java开发人员的标准做法。在上面的例子中,钩子方法hookMethod()应当以do开头;在HttpServlet类中,也遵从这一命名规则,如doGet()、doPost()等方法。


 
模板方法模式符合好莱坞设计原则:

  别调用(打电话给)我们,我们会调用(打电话给)你
  在好莱坞原则下:我们允许底层组件挂钩到系统上,但是高层组件会决定什么时候和使用这些底层组件。换句话说,高层组件对待底层组件的方式是:“别调用我,我会调用你们”
 
下面是一个冲泡咖啡和茶的例子
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public abstract class DrinkTemplet {

	public void prepareDrink(){//模板方法
		boilWater();//烧水
		brew();//冲泡
		pourIncup();//把饮料倒进杯子中
		if(CustomerNeedCondiments()){//钩子函数用来控制 模板中的方法
			String answer =getUserInput();
			addCodiemnts(answer);
		}
	}

	final void addCodiemnts(String condiments) {
		
		System.out.println("4、把"+condiments+"加入到饮料中!");
	}
	
	 String getUserInput(){
		String answer = "null";
		return answer;
	 }

	final void pourIncup() {
		
		System.out.println("3、把开水倒进杯子中!");
	}

	boolean CustomerNeedCondiments() {//钩子函数
		
		return false;
	}

	abstract void brew();

	final void boilWater() {
		
		System.out.println("1、烧热水!");
	}
	
}

  

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Tea extends DrinkTemplet{//具体的子类

	@Override
	void brew() {
		
		System.out.println("2、drop tea into the cup");
		
	}

	@Override
	boolean CustomerNeedCondiments() {
		
		boolean flag =false;
		
		System.out.println("would you like add some codiments in your tea?(y/n)");
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		try {
			if(br.readLine().startsWith("y")){
				
				flag=true;
			}
		} catch (IOException e) {
			// todo auto-generated catch block
			e.printStackTrace();
		}
		
		return flag;
		
	}
	
	 String getUserInput() {
		String answer ="null";

		try {
			System.out.println("what you want add in your tea?");
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));	
			answer =br.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return answer;
	}
	
	
	
}

  


下面是摘自别人的博客中的 模板模式的应用:来源: <http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html>

模板方法模式在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()。

 
posted @ 2015-05-19 10:13  renhq  阅读(270)  评论(0编辑  收藏  举报