`
aladdin_leon
  • 浏览: 117373 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

关于Template Method模式的思考

阅读更多

     首先让我们看看生活之中的“模板”,在《设计模式-JAVA语言中的应用》是这样说的:“模板(Template)是指在薄片塑料板上面写字(或印字)后挖空,再使用毛笔或色笔涂满挖空的部分,就能看到纯手工而又不失工整的字样。看到模板上挖空形状,马上就知道最后会变出什么样的字,不过实际上所显示出来的字样还是要依使用的画笔的种类而定。拿黑色签字笔当画笔,成果当然就是签字笔风的字样;光是铅笔来画,得到的也就是灰黑色的铅笔字;如果用五颜六色的彩色笔,自然能创造出让人眼花缭乱的多色字样。但是,无论使用那种文具,制造出来的字样都还是脱不了模板上已经固定的形状。”这个例子想必日常生活中我们都见过吧!不过这和我们要讨论的Template Method有什么关系呢?
     Template Method模式的目的:定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中。
     看一个具体的例子,假如一个工作流由三个步骤来完成,执行的顺序为123依次执行,而每一个具体的步骤可能根据具体情况会有所不同,那麽我们制造如下的一个“薄片塑料板”:     最后让我们来看看如何制作出来不同的“字体”吧!   

  1. public abstract class WorkFlow {   
  2.       public abstract void stepOne();   
  3.       public abstract void stepTwo();   
  4.       public abstract void stepThree();   
  5.       public final void work() {   
  6.           stepOne();   
  7.           stepTwo();   
  8.           stepThree();   
  9.       }   
  10. }   

     注意关键字final的意义,它意味其子类不能对工作步骤的顺序进行修改,对于abstract,我们可能意识到它并不像我们开始时认为的那麽无用了,这里的用法也是抽象类的真正含义之一。下面我们来造作两种不同的“笔风”:

  1. public class WorkFlowOne extends WorkFlow {   
  2.       public void stepOne() {   
  3.          ......   
  4.       }   
  5.       public void stepTwo() {   
  6.          ......     
  7.       }   
  8.       public void stepThree() {   
  9.          ......   
  10.       }   
  11. }   
  12.   
  13. public class WorkFlowTwo extends WorkFlow {   
  14.       public void stepOne() {   
  15.          ......   
  16.       }   
  17.       public void stepTwo() {   
  18.          ......     
  19.       }   
  20.       public void stepThree() {   
  21.          ......   
  22.       }   
  23. }  

      最后让我们来看看如何制作出来不同的“字体”吧!

  1. WorkFlow one = new WorkFlowOne();   
  2. one.work();   
  3. WorkFlow two = new WorkFlowTwo();   
  4. two.work();   

      其实学习设计模式的难点,并不是记住这个模式的类图,或者是代码框架,重要的是理解思想,说的容易做起来就很难了,我们很难识别在具体的情况下该使用什么模式,其实我们不必为此而灰心,我们可以首先让我们的代码实现功能,然后在不影响代码功能的基础之上对代码进行重新的设计,重构为合适的模式。这样对于我们使用模式的难度就会减少了很多。
     如何把自己的代码重构为模板方法模式呢?首先我们要将类似方法的框架抽象出来,并将方法框架上移至超类中,而子类只需要提供在算法的实现过程中有所区别的那些步骤。不过需要补充一下,上面的重构是基于继承的,实际应用中,我们也可以将方法框架上移至“模板类”中,通过组合来实现模板方法模式。下面就让我们实战一下吧!
     看过了《深入浅出Hibernate》后,借此对其中关于借助模板模式对DAO重构总结一下,首先我们看一个在Hibernate下典型的DAO代码模板:

  1. public class UserDAO implements IUserDAO {   
  2.        ......   
  3.        public void saveUser(final User user) {   
  4.             Session session = null;   
  5.             Transation tx = null;   
  6.             try {   
  7.                  Configuration config = new Configuration().configure();   
  8.                  SessionFactory factory = config.buildSessionFactory();   
  9.                  session = factory.openSession();   
  10.                  tx = session.beginTransaction();   
  11.                  session.save(user);   
  12.                  tx.commit();   
  13.             } catch(HibernateException e) {   
  14.                  if(tx != null) {   
  15.                      try {   
  16.                           tx.rollback();   
  17.                       } catch(HibernateException e) {   
  18.                            ......   
  19.                       }   
  20.                  }   
  21.                  ......   
  22.             } finally {   
  23.                 if(session != null) {   
  24.                      try {   
  25.                          session.close();   
  26.                      } catch(HibernateException e) {   
  27.                          ......   
  28.                      }   
  29.                 }   
  30.             }   
  31.        }   
  32.         ......   
  33.  }   

     如果继续写下去,比如deleteUser、updateUser方法,会发现大部分的代码是没有任何变化的,只有兰颜色的部分发生了变化,似乎我们嗅到了代码里面一些不好的味道...既然他们都是一样的,那麽我们就会想到是否可以进行提取而形成一个模板呢?不过这里我们用的是基于Template与Callback的方法这样可以通过组合而不是继承的方式来使用模板,至于组合和继承的怎么选择,可以看看我的2006-10-16的日志《继承还是关联?是个问题》       

  1.  public class HibernateTemlate {   
  2.         public final Object run(HibernateCallback callback) {   
  3.            Session sesion = null;   
  4.            Transaction tx = null;   
  5.            try {   
  6.               session = RootDAO.createSession();   
  7.               tx = session.beginTransaction();   
  8.               Object result = callback.execute();   
  9.               tx.commit();   
  10.               session.flush();   
  11.               return result;   
  12.            } catch(HibernateException e) {   
  13.               if(tx != null) {   
  14.                  try {   
  15.                     tx.rollback();   
  16.                  } catch(Throwable t){   
  17.                     
  18.                  } throw new RuntimeException(e);   
  19.               }   
  20.            } finally {   
  21.               if(session != null) {   
  22.                  try {   
  23.                     session.close();   
  24.                  } catch(HibernateException e) {   
  25.                     throw new RuntimeException(e);   
  26.                  }   
  27.               }   
  28.            }   
  29.         }   
  30.  }  

      下面是回调接口的定义:

  1. public interface HibernateCallback {   
  2.         Object execute() throws HibernateException;   
  3. }   

      这就是我们进行了重新设计后的UserDAO:   

  1. public class UserDAO implements IUserDAO {   
  2.       ......   
  3.       public void saveUser(final User user) {   
  4.           new HibernateTemplate().run(new HibernateCallback() {   
  5.               public Object execute() throws HibernateException {   
  6.                   UserDAO userDAO = UserDAO.getInstance();   
  7.                   return userDAO.save(user);   
  8.              }   
  9.           });   
  10.       }   
  11.       ......   
  12. }   

      现在屏住呼吸,让我们看一看这段代码,它实现了上面代码一样的功能:

  1. public class UserDAO extends HibernateDaoSupport implements IUserDAO {   
  2.       public void saveUser(User user) {   
  3.            getHibernateTemplate().saveOrUpdate(user);   
  4.       }   
  5.       ......   
  6. }   

     你是不是有一点惊异呢!简直太简单了,这就是Spring+Hiberbate带给我们的春天,这里并没有详细介绍如何配置上面的代码,我们只是看一下冰山一角,就已经足够见识其简单性和纯洁性了,代码只关心最重要的业务逻辑,而不用在为繁杂的异常处理和事务声明而费心了。这里Spring利用的也恰恰是Template Method模式!
     不知道为什么写完这篇文章,好像对设计模式的认识清晰了一些,又好像更加模糊了,也许“道”亦有道...这其中的玄机也许只有靠每日的积累才能真正领悟吧...

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics