Template Method模式的目的:定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中。
看一个具体的例子,假如一个工作流由三个步骤来完成,执行的顺序为123依次执行,而每一个具体的步骤可能根据具体情况会有所不同,那麽我们制造如下的一个“薄片塑料板”: 最后让我们来看看如何制作出来不同的“字体”吧!
- public abstract class WorkFlow {
- public abstract void stepOne();
- public abstract void stepTwo();
- public abstract void stepThree();
- public final void work() {
- stepOne();
- stepTwo();
- stepThree();
- }
- }
注意关键字final的意义,它意味其子类不能对工作步骤的顺序进行修改,对于abstract,我们可能意识到它并不像我们开始时认为的那麽无用了,这里的用法也是抽象类的真正含义之一。下面我们来造作两种不同的“笔风”:
- public class WorkFlowOne extends WorkFlow {
- public void stepOne() {
- ......
- }
- public void stepTwo() {
- ......
- }
- public void stepThree() {
- ......
- }
- }
- public class WorkFlowTwo extends WorkFlow {
- public void stepOne() {
- ......
- }
- public void stepTwo() {
- ......
- }
- public void stepThree() {
- ......
- }
- }
最后让我们来看看如何制作出来不同的“字体”吧!
- WorkFlow one = new WorkFlowOne();
- one.work();
- WorkFlow two = new WorkFlowTwo();
- two.work();
其实学习设计模式的难点,并不是记住这个模式的类图,或者是代码框架,重要的是理解思想,说的容易做起来就很难了,我们很难识别在具体的情况下该使用什么模式,其实我们不必为此而灰心,我们可以首先让我们的代码实现功能,然后在不影响代码功能的基础之上对代码进行重新的设计,重构为合适的模式。这样对于我们使用模式的难度就会减少了很多。
如何把自己的代码重构为模板方法模式呢?首先我们要将类似方法的框架抽象出来,并将方法框架上移至超类中,而子类只需要提供在算法的实现过程中有所区别的那些步骤。不过需要补充一下,上面的重构是基于继承的,实际应用中,我们也可以将方法框架上移至“模板类”中,通过组合来实现模板方法模式。下面就让我们实战一下吧!
看过了《深入浅出Hibernate》后,借此对其中关于借助模板模式对DAO重构总结一下,首先我们看一个在Hibernate下典型的DAO代码模板:
- public class UserDAO implements IUserDAO {
- ......
- public void saveUser(final User user) {
- Session session = null;
- Transation tx = null;
- try {
- Configuration config = new Configuration().configure();
- SessionFactory factory = config.buildSessionFactory();
- session = factory.openSession();
- tx = session.beginTransaction();
- session.save(user);
- tx.commit();
- } catch(HibernateException e) {
- if(tx != null) {
- try {
- tx.rollback();
- } catch(HibernateException e) {
- ......
- }
- }
- ......
- } finally {
- if(session != null) {
- try {
- session.close();
- } catch(HibernateException e) {
- ......
- }
- }
- }
- }
- ......
- }
如果继续写下去,比如deleteUser、updateUser方法,会发现大部分的代码是没有任何变化的,只有兰颜色的部分发生了变化,似乎我们嗅到了代码里面一些不好的味道...既然他们都是一样的,那麽我们就会想到是否可以进行提取而形成一个模板呢?不过这里我们用的是基于Template与Callback的方法这样可以通过组合而不是继承的方式来使用模板,至于组合和继承的怎么选择,可以看看我的2006-10-16的日志《继承还是关联?是个问题》
- public class HibernateTemlate {
- public final Object run(HibernateCallback callback) {
- Session sesion = null;
- Transaction tx = null;
- try {
- session = RootDAO.createSession();
- tx = session.beginTransaction();
- Object result = callback.execute();
- tx.commit();
- session.flush();
- return result;
- } catch(HibernateException e) {
- if(tx != null) {
- try {
- tx.rollback();
- } catch(Throwable t){
- } throw new RuntimeException(e);
- }
- } finally {
- if(session != null) {
- try {
- session.close();
- } catch(HibernateException e) {
- throw new RuntimeException(e);
- }
- }
- }
- }
- }
下面是回调接口的定义:
- public interface HibernateCallback {
- Object execute() throws HibernateException;
- }
这就是我们进行了重新设计后的UserDAO:
- public class UserDAO implements IUserDAO {
- ......
- public void saveUser(final User user) {
- new HibernateTemplate().run(new HibernateCallback() {
- public Object execute() throws HibernateException {
- UserDAO userDAO = UserDAO.getInstance();
- return userDAO.save(user);
- }
- });
- }
- ......
- }
现在屏住呼吸,让我们看一看这段代码,它实现了上面代码一样的功能:
- public class UserDAO extends HibernateDaoSupport implements IUserDAO {
- public void saveUser(User user) {
- getHibernateTemplate().saveOrUpdate(user);
- }
- ......
- }
你是不是有一点惊异呢!简直太简单了,这就是Spring+Hiberbate带给我们的春天,这里并没有详细介绍如何配置上面的代码,我们只是看一下冰山一角,就已经足够见识其简单性和纯洁性了,代码只关心最重要的业务逻辑,而不用在为繁杂的异常处理和事务声明而费心了。这里Spring利用的也恰恰是Template Method模式!
不知道为什么写完这篇文章,好像对设计模式的认识清晰了一些,又好像更加模糊了,也许“道”亦有道...这其中的玄机也许只有靠每日的积累才能真正领悟吧...