转自独立blog《Adrop的自留地》
—-Head First Pattern之模板方法模式
这年头大家都用struts,或者其他MVC框架,很少有人直接用Servlet了吧,但是相信大部分人都应该知道怎么写Servlet的吧,继承HttpServlet类,覆盖里面的doGet、doPost方法即可,大部分情况下,我们都是对GET和POST一样处理,一般也就这么写了:
public MyServlet extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponse response){
// 处理
}
public void doPost()HttpServletRequest request, HttpServletResponse response){
// 不关心get、post请求,因此post处理直接调用get处理
doGet(request, response);
}
}
Servlet只要在web.xml中部署好之后,就可以处理浏览器的请求了。上面代码可以看出来,doGet方法处理浏览器的GET请求,doPost处理POST请求。
Servlet是由Tomcat之类的servlet容器来调用处理浏览器请求的,并需要集成基类HttpServlet,如果大家查看HttpServlet源码的时候,就会发现,其实里面有一个
protectedvoid service(HttpServletRequest req, HttpServletResponse resp)
方法,servlet容器实际调用的是service方法,service方法的实现就是根据HTTP请求的类型(GET、POST,还是其他),将处理委派给doGet、doPost等方法,由这些子类的方法来最终处理浏览器的请求。
由此可以看出,HttpServlet定义了一个处理的框架或者说模板,实现Servlet只需继承HttpServlet并实现doGet、doPost等方法即可。
是引出模板方法模式定义的时候了,模板方法模式:在一个方法中定义一个算法的骨架,将某些步骤推迟到子类中实现。模板方法允许子类重新定义算法的某些步骤,而不改变算法的结构。
简单UML类图如下:
简单实现一个抽象类:
public abstract Template{
public void final templateMethod(){
step1();
step2();
hook();
}
public abstract void step1();
public abstract void step2();
public void hook(){}
}
这个抽象类,定义了一个算法的骨架,需要step1、step2,都是抽象方法,需要子类来实现。而templateMethod是final的,即不允许子类覆盖。其中定义了方法的步骤,step1、step2。
如下为具体实现:
public ConcreteTemplate extends Template{
public void step1(){System.out.println(“step1″);}
public void step2(){System.out.println(“step2″);}
public void hook(){System.out.println(“hook”);}
public static void main(String[] args){
Template temp = new ConcreteTemplate();
temp.templateMethod();
}
}
可以看到其中加入了一个hook方法,即钩子方法。hook方法在抽象类中的实现为空,是留给子类做一些可选的操作。如果某个子类需要一些特殊额外的操作,则可以实现hook方法,当然也可以完全不用理会,因为hook在抽象类中只是空方法而已。
其他扩展:
1.可以定义多个hook方法
2.hook方法可以定义一个返回为boolean的方法,有子类来决定是否调用hook方法。
eg:抽象类的templateMethod可以这样实现:
public void final templateMethod(){
step1();
step2();
if(allowHook())
hook();
}
public boolean allowHook(){return true;}
public void hook(){}
子类中可以覆盖allowHook,以决定是否调用hook方法。
3.抽象类定义的步骤,可以有默认实现,而非全是abstract方法。HttpServlet中已经有doGet、doPost等方法的默认实现,大家可以参考其源码实现。
更好的一个模板方法的例子是Applet,实现自己的Applet,必须继承自Applet,里面实现init、start、stop、destroy等方法即可。这些方法都是有默认实现的,如果看源码,可以发现默认实现其实都是空。
了解模板方法模式之后,大家可能意识到Servlet并且完全按照模板方法定义的那样,而是有一些区别,比如提供默认doGet、doPost的实现等。这都说明,在实际编程中,并非生搬硬套设计模式,而是根据实际,会做些变动或变形,但其本质不变。
不能为了模式而模式。那究竟什么时候需要设计模式呢?个人理解,当你发现你的类有问题的时候,比如有重复代码了,感觉有些不对劲了,感觉不适应以后的扩充了,这时候不妨考虑下,是不是该设计模式出场了。。
纯粹个人理解。。有不当之处,请及时拍砖。。