首页 > 其他分享 >模板方法

模板方法

时间:2023-10-13 13:11:56浏览次数:24  
标签:status ... 子类 void 方法 public 模板

概述

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

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

代码演示

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,这就体现了设计模式的开闭原则,通过继承或者组合的方式进行扩展,而不是直接修改类的代码。

标签:status,...,子类,void,方法,public,模板
From: https://www.cnblogs.com/haveanicedayfh/p/17761842.html

相关文章

  • EasyMock 使用方法与原理剖析
    https://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/ Mock方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较复杂的对象,从而把测试与测试边界以外的对象隔离开。编写自定义的Mock对象需要额外的编码工作,同时也可能引入错误。Ea......
  • react中关于父子组件传值已经方法调用总结
    问题:1、封装自定义组件后,父子组件的传值与方法调用则是必须进行的操作,但是在网上看到多种的方法后,有的方法一个组件下好使,但是换一个组件后就不好用了有的方法根本就不好使,不知道是什么原因2、父子组件之间的传值都是用props这个毫无疑问,也没有什么问题3、父子组件方法调用......
  • Html5大文件断点续传实现方法
    大文件分块一般常用的web服务器都有对向服务器端提交数据有大小限制。超越一定大小文件服务器端将返回拒绝信息。当然,web服务器都提供了配置文件可能修改限制的大小。针对ii实现大文件的上传网上也有一些通过修改web服务器限制文件大小来实现。不过这样对web服务器的平安带了问题......
  • docker中使用systemctl方法
    想在docker中使用Flexmonster,但是在配置环境后,发现Flexmonster需要使用systemctl来管理服务,然而在docker容器中没有systemctl可用,于是开始折腾之旅!以下是解决办法:1、下载systemctlwgethttps://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/d......
  • 06 模板语法
    template:模板主要讲的是vue的基本使用语法1.文本插值和js的结合使用2.原始HTML......
  • /usr/bin/ld: cannot find -lxxx 的解决方法总结
    问题原因:1、系统没有按照相应的lib2、相对应的lib版本不对3、lib的symboliclink不对,没有连接到正确的函数库文件(so)解决:对于1,2种情况:apt-getinstalllibxxx-dev对于3中情况:可以先用locate和find找到指定的lib文件,查看链接文件是否正确的指向了我们希望的lib,如果不是,......
  • SQL注入一些方法
    select(ascii(substr(database(),1,1)))>91这个查询语句的目的是检查数据库名的第一个字符的ASCII码是否大于91。让我们分解这个查询以便更好地理解它的含义:database():这是一个MySQL函数,用于返回当前数据库的名称。substr(database(),1,1):这是一个MySQL函数,用于从数据库名称......
  • List 的 6 种去重方法
    1HashSet去重我们知道HashSet天生具备“去重”的特性,那我们只需要将List集合转换成HashSet集合就可以了,实现代码如下:publicclassListDistinctExample{publicstaticvoidmain(String[]args){List<Integer>list=newArrayList<Integer>(){{......
  • burpsuite靶场----CSRF----token验证取决于请求方法
    burpsuite靶场----CSRF----无防御靶场地址https://portswigger.net/web-security/csrf/bypassing-token-validation/lab-token-validation-depends-on-request-method正式开始1.登录2.抓包,发现有一段token3.尝试删掉token,发现不行4.尝试改变请求方式发现也能实现功......
  • 类里面静态方法(@staticmethod),类方法(@classmethod)和实例方法(self)的使用与区别
    前言python类里面常用的方法有3个:静态方法(@staticmethod),类方法(@classmethod)和实例方法(self)本篇讲解这3种方法在使用上有什么区别。函数先从函数说起,方法跟函数是有区别的,经常有人容易混淆,函数定义是def关键字定义(外面没class)deffun():a="hello"returna#......