>  기사  >  Java  >  Java 템플릿 및 콜백 메커니즘에 대한 자세한 설명

Java 템플릿 및 콜백 메커니즘에 대한 자세한 설명

高洛峰
高洛峰원래의
2017-01-24 13:37:241223검색

최근 Spring JDBCTemplete의 템플릿 메소드를 살펴보면서 템플릿과 콜백에 관심이 많아 몇 가지 정보를 쿼리하고 요약했습니다.

콜백 함수:

소위 콜백이란 클라이언트 프로그램 C가 서비스 프로그램 S의 함수 A를 호출한 다음 S가 특정 시점에 C의 함수 B를 호출하는 것을 의미합니다. time., C의 경우 이 B를 콜백 함수라고 합니다. 콜백 함수는 콜백 함수 호출 규칙에 따라 사용자가 구현한 함수인 기능적 단편일 뿐입니다. 콜백 함수는 워크플로의 일부이며 워크플로에 따라 함수 호출(콜백) 타이밍이 결정됩니다. 일반적으로 C는 B를 스스로 호출하지 않습니다. C가 B를 호출하는 목적은 S가 호출하도록 하는 것이며 C는 이를 제공해야 합니다. S는 C가 제공한 B의 이름을 모르기 때문에 S는 B의 인터페이스 사양(함수 프로토타입)에 동의하고, 그러면 C는 S의 함수 R을 통해 B 함수를 사용할 것임을 미리 S에게 알려준다. 프로세스를 콜백이라고 하며, R을 등록된 함수라고 합니다. 웹 서비스와 Java의 RMI는 모두 콜백 메커니즘을 사용하여 원격 서버 프로그램에 액세스합니다. 콜백 함수에는 다음과 같은 특징이 있습니다.

1. 워크플로의 일부입니다.

2. 워크플로에서 지정한 호출 규칙에 따라 선언(정의)되어야 합니다. 🎜>

3. 콜백 함수 구현자는 워크플로 기능을 구현하기 위해 콜백 함수를 직접 호출할 수 없습니다.

콜백 메커니즘:

콜백 메커니즘은 일반적입니다. 디자인 모델은 합의된 인터페이스에 따라 워크플로 내의 특정 기능을 외부 사용자에게 노출하거나, 외부 사용자에게 데이터를 제공하거나, 외부 사용자에게 데이터 제공을 요구합니다.

Java 콜백 메커니즘:

소프트웨어 모듈 간에는 항상 특정 인터페이스가 있습니다. 호출 방법 측면에서 동기 호출, 콜백 및 비동기 호출의 세 가지 범주로 나눌 수 있습니다.

동기 호출: 호출자는 상대방이 실행을 완료할 때까지 기다려야 반환할 수 있습니다.

콜백: 양방향 호출 모드입니다. 즉, 인터페이스가 호출될 때 수신자가 상대방의 인터페이스도 호출한다고 합니다.

비동기 호출: 메시지나 이벤트와 유사한 메커니즘이지만 호출 방향은 정반대의 서비스입니다. 인터페이스는 특정 메시지나 이벤트가 발생하면 클라이언트에 사전에 알림을 보냅니다(즉, 클라이언트의 인터페이스가 호출됩니다).

콜백과 비동기 호출은 밀접하게 관련되어 있습니다. 콜백은 비동기 메시지를 등록하는 데 사용되고 비동기 호출은 메시지를 알리는 데 사용됩니다.

콜백 인스턴스

1. 콜백 인터페이스

public interface Callback {
 
   String callBack();
 }

2. 호출자

3. 콜백 함수

public class Another {
  private Callback callback;
  //调用实现类的方法
  public void setCallback(Callback callback) {
    this.callback = callback;
  }
    //业务需要的时候,通过委派,来调用实现类的具体方法
  public void doCallback(){
    System.out.println(callback.callBack());
  }
}

콜백 메서드의 사용은 일반적으로 "java 인터페이스" 및 "추상 클래스" 사용 중에 발생합니다. 템플릿 메소드 디자인 패턴은 메소드 콜백 메커니즘을 사용합니다. 이 패턴은 먼저 특정 단계의 알고리즘 뼈대를 정의하고 구현을 위해 일부 단계를 하위 클래스로 연기합니다. 템플릿 메소드 디자인 패턴을 사용하면 서브클래스가 알고리즘의 구조를 변경하지 않고도 알고리즘의 특정 단계를 재정의할 수 있습니다.

템플릿 디자인 패턴의 적용 가능성:

1. 알고리즘의 상수 부분은 한번에 구현하고, 가변 알고리즘은 하위 클래스에 구현하도록 남겨둔다.

2. 코드 중복을 피하기 위해 각 하위 클래스의 공통 동작을 추출하고 공통 상위 클래스에 집중해야 합니다.

3. 하위 클래스 확장을 제어할 수 있습니다.

템플릿 인스턴스:

추상 템플릿 메서드 클래스:

public class TestCallcack {
  public static void main(String[] args) {
    //创建调用者的实现类
    Another another = new Another();
    //将回掉接口注册到实现类中
    another.setCallback(new Callback() { 
      @Override
      public String callBack() {
        return "you are a pig";
      }
    });
    //执行回调函数
    another.doCallback();
  }
}

하위 클래스 구현 템플릿 메서드 클래스:

public abstract class AbstractSup {
    //需要子类实现的方法
  public abstract void print();
    //模板方法
  public void doPrint(){
    System.out.println("执行模板方法");
    for (int i = 0; i < 3; i++) {
      print();
    }
  }
}

템플릿 메소드 테스트 클래스:

public class SubClass extends AbstractSup{
  @Override
  public void print() {
    System.out.println("子类的实现方法");
  }
 
}

다음은 JdbcTemplete를 예로 들어 템플릿 패턴 및 콜백 메커니즘의 사용에 대한 심층적인 소개입니다. 자세히 설명되어 있습니다.

먼저 고전적인 JDBC 프로그래밍 예제를 살펴보겠습니다.

public class TempleteTest {
  public static void main(String[] args) {
    SubClass subClass = new SubClass();
    subClass.print();
    subClass.doPrint();
  }
}

간단한 쿼리는 많은 작업을 수행해야 하며 예외도 처리해야 합니다.

1 . 연결 가져오기

2. 문 가져오기
3. 결과 집합 가져오기
4. 결과 집합을 탐색하여 컬렉션으로 캡슐화합니다
5. 연결, 문 및 결과 집합을 순서대로 닫습니다. 다양한 예외 등을 고려하십시오. 기다리십시오.

여러 쿼리로 인해 더 많은 중복 코드가 생성되는 경우 이때 템플릿 메커니즘을 사용할 수 있습니다. 관찰을 통해 위 단계의 대부분이 ResultSet을 순회할 때만 반복되고 재사용 가능하다는 것을 발견했습니다. 각 테이블이 서로 다른 Java Bean을 매핑하기 때문에 이를 컬렉션으로 사용자 정의할 수 있습니다. 이 코드 부분은 재사용할 수 없으며 사용자 정의만 가능합니다.

추상 클래스 코드:

public List<User> query() {
  
  List<User> userList = new ArrayList<User>();
  String sql = "select * from User";
  
  Connection con = null;
  PreparedStatement pst = null;
  ResultSet rs = null;
  try {
    con = HsqldbUtil.getConnection();
    pst = con.prepareStatement(sql);
    rs = pst.executeQuery();
  
    User user = null;
    while (rs.next()) {
  
      user = new User();
      user.setId(rs.getInt("id"));
      user.setUserName(rs.getString("user_name"));
      user.setBirth(rs.getDate("birth"));
      user.setCreateDate(rs.getDate("create_date"));
      userList.add(user);
    }
  
  
  } catch (SQLException e) {
    e.printStackTrace();
  }finally{
    if(rs != null){
      try {
        rs.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    try {
      pst.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
    try {
      if(!con.isClosed()){
        try {
          con.close();
       } catch (SQLException e) {
          e.printStackTrace();
        }
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }
      
  }
  return userList;
}

이 추상 클래스는 SUN JDBC API의 주요 프로세스를 캡슐화하며 ResultSet을 순회하는 단계는 다음과 같습니다. 이를 추상 메서드 doInStatement()에 넣으면 하위 클래스가 이를 구현합니다.

하위 클래스 구현 코드:

public abstract class JdbcTemplate {
  
  //模板方法
  public final Object execute(String sql) throws SQLException{
    
    Connection con = HsqldbUtil.getConnection();
    Statement stmt = null;
    try {
   
      stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery(sql);
      Object result = doInStatement(rs);//抽象方法(定制方法,需要子类实现) 
      return result;
    }
    catch (SQLException ex) {
       ex.printStackTrace();
       throw ex;
    }
    finally {
   
      try {
        stmt.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
      try {
        if(!con.isClosed()){
          try {
            con.close();
          } catch (SQLException e) {
            e.printStackTrace();
          }
        }
      } catch (SQLException e) {
        e.printStackTrace();
      }
        
    }
  }
    
  //抽象方法(定制方法)
  protected abstract Object doInStatement(ResultSet rs);
}

doInStatement() 메서드에서 ResultSet를 순회하고 마지막으로 반환합니다.

테스트 코드:

public class JdbcTemplateUserImpl extends JdbcTemplate {
  
  @Override
  protected Object doInStatement(ResultSet rs) {
    List<User> userList = new ArrayList<User>();
      
    try {
      User user = null;
      while (rs.next()) {
  
        user = new User();
        user.setId(rs.getInt("id"));
        user.setUserName(rs.getString("user_name"));
        user.setBirth(rs.getDate("birth"));
        user.setCreateDate(rs.getDate("create_date"));
        userList.add(user);
      }
      return userList;
    } catch (SQLException e) {
      e.printStackTrace();
      return null;
    }
  }
  
}

템플릿 메커니즘의 사용은 여기서 끝나지만 jdbcTemplate을 호출할 때마다 위의 상위 클래스를 상속받아야 한다면 그렇지 않습니다. 매우 편리합니다. 이렇게 하면 콜백 메커니즘이 작동할 수 있습니다.

所谓回调,就是方法参数中传递一个接口,父类在调用此方法时,必须调用方法中传递的接口的实现类。

回调加模板模式实现

回调接口:

public interface StatementCallback {
  Object doInStatement(Statement stmt) throws SQLException;
 }

 模板方法:

public class JdbcTemplate {
  
  //模板方法
  public final Object execute(StatementCallback action) throws SQLException{
      
    Connection con = HsqldbUtil.getConnection();
    Statement stmt = null;
    try {
   
      stmt = con.createStatement();
      Object result = action.doInStatement(rs);//回调方法
      return result;
    }
    catch (SQLException ex) {
       ex.printStackTrace();
       throw ex;
    }
    finally {
   
      try {
        stmt.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
      try {
        if(!con.isClosed()){
          try {
            con.close();
          } catch (SQLException e) {
            e.printStackTrace();
          }
        }
      } catch (SQLException e) {
        e.printStackTrace();
      }
        
    }
  }    
  }
  public Object query(StatementCallback stmt) throws SQLException{
    return execute(stmt);
  }
}

   

测试的类:

public Object query(final String sql) throws SQLException {
    class QueryStatementCallback implements StatementCallback {
  
      public Object doInStatement(Statement stmt) throws SQLException {
        ResultSet rs = stmt.executeQuery(sql);
        List<User> userList = new ArrayList<User>();
  
        User user = null;
        while (rs.next()) {
  
          user = new User();
          user.setId(rs.getInt("id"));
          user.setUserName(rs.getString("user_name"));
          user.setBirth(rs.getDate("birth"));
          user.setCreateDate(rs.getDate("create_date"));
          userList.add(user);
        }
        return userList;
  
      }
  
    }
  
    JdbcTemplate jt = new JdbcTemplate();
    return jt.query(new QueryStatementCallback());
  }

   


为什么spring不用传统的模板方法,而加之以Callback进行配合呢? 
试想,如果父类中有10个抽象方法,而继承它的所有子类则要将这10个抽象方法全部实现,子类显得非常臃肿。而有时候某个子类只需要定制父类中的某一个方法该怎么办呢?这个时候就要用到Callback回调了。

另外,上面这种方式基本上实现了模板方法+回调模式。但离spring的jdbcTemplate还有些距离。 我们上面虽然实现了模板方法+回调模式,但相对于Spring的JdbcTemplate则显得有些“丑陋”。Spring引入了RowMapper和ResultSetExtractor的概念。 RowMapper接口负责处理某一行的数据,例如,我们可以在mapRow方法里对某一行记录进行操作,或封装成entity。 ResultSetExtractor是数据集抽取器,负责遍历ResultSet并根据RowMapper里的规则对数据进行处理。 RowMapper和ResultSetExtractor区别是,RowMapper是处理某一行数据,返回一个实体对象。而ResultSetExtractor是处理一个数据集合,返回一个对象集合。

  当然,上面所述仅仅是Spring JdbcTemplte实现的基本原理,Spring JdbcTemplate内部还做了更多的事情,比如,把所有的基本操作都封装到JdbcOperations接口内,以及采用JdbcAccessor来管理DataSource和转换异常等。

以上就是本文的全部内容,希望对大家的学习有所帮助。

更多详解java模板和回调机制相关文章请关注PHP中文网!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.