行为型设计模式:模板模式

时间:2022-07-23
本文章向大家介绍行为型设计模式:模板模式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

模板模式是常用的一种行为型设计模式,主要思想是在模板中定义一套流程骨架代码,并且不实现骨架代码中使用的一些方法,这些方法留给子类去实现。假如我们业务开发中有一个场景,我们的业务系统需要从不同征信渠道查询征信报告,每家机构输出的内容不一样,但是都分为3个步骤,建立连接、获取报告原始内容、解析报告并入库。这样,我们定义一个模板类:

public abstract class AbstractReportTemplate {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    public final void doTask(){
        doConnect();
        getReport();
        parseRepot();
    }

    /**
     * 建立连接
     */
    public abstract void doConnect();

    /**
     * 获取报告
     */
    public abstract void getReport();

    /**
     * 解析报告并落库
     */
    public abstract void parseRepot();
}

假如我们现在要对接A征信机构,那我们只要继承这个模板类,实现上面的抽象方法就可以了,任务流程不变。

public class AReport extends AbstractReportTemplate {

    public void doConnect() {
        logger.info("do connect");
    }

    public void getReport() {
        logger.info("get report");
    }

    public void parseRepot() {
        logger.info("parseReport");
    }
}

方法调用:

public static void main(String[] args){
        AbstractReportTemplate aReport = new AReport();
        aReport.doTask();
    }

可见,模板模式实现起来非常简单。下面我介绍几个源码中的模板模式。

1.jdk中的InputStream类就是一个模板类,里面定义了抽象read方法

public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }
    
    public abstract int read() throws IOException;

实现类有好多,如下图:

下面是ByteArrayInputStream的实现:

public synchronized int read() {
        return (pos < count) ? (buf[pos++] & 0xff) : -1;
    }

2.jdbc中的AbstractDataSourceInitializer用来初始化数据源

@PostConstruct
  protected void initialize() {
    if (!isEnabled()) {
      return;
    }
    ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
    String schemaLocation = getSchemaLocation();
    if (schemaLocation.contains(PLATFORM_PLACEHOLDER)) {
      String platform = getDatabaseName();
      schemaLocation = schemaLocation.replace(PLATFORM_PLACEHOLDER, platform);
    }
    populator.addScript(this.resourceLoader.getResource(schemaLocation));
    populator.setContinueOnError(true);
    customize(populator);
    DatabasePopulatorUtils.execute(populator, this.dataSource);
  }
  
  protected abstract DataSourceInitializationMode getMode();

  protected abstract String getSchemaLocation();

BatchDataSourceInitializer中的实现

@Override
  protected DataSourceInitializationMode getMode() {
    return this.properties.getInitializeSchema();
  }

  @Override
  protected String getSchemaLocation() {
    return this.properties.getSchema();
  }

文中源码:https://github.com/jinjunzhu/design-pattern.git