设计模式之模板方法模式――用模板方法来实现所有servlet的session判断

晚上回宿舍还没开门呢就直奔Tony的宿舍,跟他抱怨起今天碰到的问题来:做了很多servlet,我发现总是在每个servlet里都要判断session值来检测用户是否有权限,今天就因为session问题搞了半天,太恼火了。当然,要是别人,可能就只是同情下。但是对于技术有着狂热爱好的Tony就不一样:总有解决办法,等我想想……对了,这是典型的模板方法….. 何为模板方法:GOF给模板方法(Template Method)模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 定义总是绕口的,不然怎能忽悠大众呢对吧?先撇开定义不说,来看看我们具体的实例: 其实我想要的功能很简单,就是在执行每个servlet的doGet或doPost之前执行一段固定的代码,这段代码的作用是检查session来判断权限。那好,现在的结构就是如下: [java] protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException { checkSession(); doBussiness(request, response); //这里就是我这个servlet真正要做的业务逻辑 } [/java] 看了以上代码,最先想到的是什么?对,就是先定义一个静态方法checkSession,然后在每个servlet的doGet或doPost之前加上checkSession的调用不就完了嘛。 可实际是,我不想动每个servlet里的代码啊。最关键的是,servlet不是我一个人写的,其他人要是不调用checkSession方法呢?或者说要是忘了呢?测试肯定通过,但是不安全的隐患却留下了。。。 过了一会,Tony拿着一段代码过来了。 [java] abstract class ServletBase extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { checkSession(); doBussiness(request, response); } abstract void doBussiness(HttpServletRequest request, HttpServletResponse response); } public class MyServlet extends ServletBase { public void doBussiness(HttpServletRequest request, HttpServletResponse response) { // TODO Auto-generated method stub } } [/java] 这样,在执行MyServlet的时候首先会找doGet方法,结果呢,当然是在MyServlet类里找不到,这时候就去找它的父类,也就是我们定义的ServletBase类。好,这时候找到父类的doGet方法了,它就执行这个doGet。首先执行checkSession,然后doBussiness,由于我们在ServletBase里只是定义了一个doBussiness的抽象方法,它就返回到MyServlet找这个方法的实现,结果是调用了我们真正的业务逻辑。这样就完成了我最初的愿望:在执行每个servlet的doGet或doPost之前执行一段固定的代码。这段代码不用我每次写进doGet或doPost里。而我要做的是,仅仅让我的MyServlet继承我自己写的ServletBase类(而不是servlet本身的HttpServlet)。 实际上,模板方法模式的作用不仅仅于此,但是从这一个简单实用的实例我们已经了解了模板方法模式是怎么回事了,下面是一些比较有头有脸的定义和说明: GOF给模板方法(Template Method)模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这里的算法的结构,可以理解为你根据需求设计出来的业务流程。特定的步骤就是指那些可能在内容上存在变数的环节。 其结构图如下: 11111111111111111111 1) AbstractClass(抽象类)(在我们的实例中就是ServletBase类):定义了一到多个的抽象方法,以供具体的子类来实现它们(在我们的实例中就是ServletBase.doBussiness()方法);而且还要实现一个模板方法,来定义一个算法的骨架(在我们的实例中就是ServletBase.doGet()方法)。该模板方法不仅调用前面的抽象方法,也可以调用其他的操作,只要能完成自身的使命。 2) ConcreteClass(具体类)(在我们的实例中就是MyServlet类):实现父类中的抽象方法以完成算法中与特定子类相关的步骤(在我们的实例中就是MyServlet.doBussiness()方法)。