模板方法

发布时间 2023-10-13 13:01:27作者: haveanicedayfh

概述

在模板方法模式中,可以将子类共性的部分放在父类中实现,而特性的部分延迟到子类中实现,只需将特性部分在父类中声明成抽象方法即可,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤,不同的子类可以以不同的方式来实现这些逻辑。(在模板方法模式中,我们可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中,从而解决代码重复的问题。)

模板方法模式的优点在于符合“开闭原则”,也能够实现代码复用,将不变的行为转移到父类,去除子类中的重复代码。

代码演示

package com.fh.templates;

import org.junit.Test;

public class TemplatesTest {
    @Test
    public void m() {
        ExaminationPape pape = new Student();
        pape.result();
        System.out.println("--------------");

        pape = new Teacher();
        pape.result();
    }

    abstract class ExaminationPape {
        public void result() {
            System.out.println("1+1=" + answer1());
            System.out.println("1+2=" + answer2());
            System.out.println("1-1=" + answer3());
        }

        public abstract String answer1();

        public abstract String answer2();

        public abstract String answer3();
    }

    class Student extends ExaminationPape {

        @Override
        public String answer1() {
            return "2";
        }

        @Override
        public String answer2() {
            return "4";
        }

        @Override
        public String answer3() {
            return "1";
        }
    }

    class Teacher extends ExaminationPape {

        @Override
        public String answer1() {
            return "2";
        }

        @Override
        public String answer2() {
            return "3";
        }

        @Override
        public String answer3() {
            return "0";
        }
    }
}

使用场景

spring 事务

源码解析

AbstractPlatformTransactionManager类

//模板方法doRollback(),把重要的步骤延迟到子类去实现
protected abstract void doRollback(DefaultTransactionStatus status) throws TransactionException;
 
//模板方法doCommit(),把重要的步骤延迟到子类去实现
protected abstract void doCommit(DefaultTransactionStatus status) throws TransactionException;

@Override
public final void commit(TransactionStatus status) throws TransactionException {
    //省略...
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    if (defStatus.isLocalRollbackOnly()) {
        //省略...
        //调用processRollback()
        processRollback(defStatus, false);
        return;
    }
 
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
        //省略...
        //调用processRollback()
        processRollback(defStatus, true);
        return;
    }
    //调用processCommit()
    processCommit(defStatus);
}
 
//这个方法定义了骨架,里面会调用一个doRollback()的模板方法
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    if (status.hasSavepoint()) {
        //省略...
    }
    else if (status.isNewTransaction()) {
        //调用doRollback()模板方法
        doRollback(status);
    }
    else {
        //省略...
    }
    //省略了很多代码...
}
 
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    //省略...
    if (status.hasSavepoint()) {
        //省略...
    }
    else if (status.isNewTransaction()) {
        //省略...
        //调用doCommit()模板方法
        doCommit(status);
    }
    else if (isFailEarlyOnGlobalRollbackOnly()) {
        unexpectedRollback = status.isGlobalRollbackOnly();
    }
    //省略了很多代码...
}

其实模板模式在日常开发中也经常用,比如一个方法中,前后代码都一样,只有中间有一部分操作不同,就可以使用模板模式进行优化代码,这可以大大地减少冗余的代码,非常实用。

DataSourceTransactionManager

模板方法则由各种事务管理器的实现类去实现,也就是把骨架中重要的doRollback()延迟到子类。一般来说,Spring默认是使用的事务管理器的实现类是DataSourceTransactionManager。

//通过继承AbstractPlatformTransactionManager抽象类
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {
    //重写doCommit()方法,实现具体commit的逻辑
    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
        Connection con = txObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            logger.debug("Committing JDBC transaction on Connection [" + con + "]");
        }
        try {
            con.commit();
        }
        catch (SQLException ex) {
            throw new TransactionSystemException("Could not commit JDBC transaction", ex);
        }
    }
    
    //重写doRollback()方法,实现具体的rollback的逻辑
    @Override
    protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
      logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
    }
    try {
      con.rollback();
    }
    catch (SQLException ex) {
      throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    }
  }
}

如果你是用Hibernate框架,Hibernate也有自身的实现HibernateTransactionManager,这就体现了设计模式的开闭原则,通过继承或者组合的方式进行扩展,而不是直接修改类的代码。