搜尋
首頁Javajava教程詳解java模板和回呼機制

最近看spring的JDBCTemplete的模板方式調用時,對模板和回調產生了濃厚興趣,查詢了一些資料,做一些總結。

回呼函數:

  所謂回調,就是客戶程式C呼叫服務程式S中的某個函數A,然後S又在某個時候反過來呼叫C中的某個函數B,對於C來說,這個B便叫做回呼函數。回調函數只是一個功能片段,由使用者依照回呼函數呼叫約定來實現的一個函數。回呼函數是一個工作流程的一部分,由工作流程決定函數的呼叫(回呼)時機。一般說來,C不會自己呼叫B,C提供B的目的就是讓S來呼叫它,而且是C不得不提供。由於S不知道C提供的B姓甚名誰,所以S會約定B的介面規格(函數原型),然後由C事先透過S的一個函數R告訴S自己將要使用B函數,這個過程稱為回調函數的註冊,R稱為註冊函數。 Web Service以及Java 的RMI都用到回呼機制,可以存取遠端伺服器程式。回呼函數包含以下幾個特性:

    1、屬於工作流程的一個部分;

    2、必須依照工作流程指定的呼叫約定來申明(定義);

    3、他的呼叫回呼函數的實現者不能直接呼叫回呼函數來實現工作流程的功能; 

回呼機制:

回呼機制是一種常見的設計模型,他把工作流程內的某個功能,依照約定的介面暴露給外部使用者,為外部用戶提供數據,或要求外部用戶提供數據。

java回呼機制:

軟體模組之間總是存在著一定的接口,從調用方式上,可以把他們分為三類:同步調用、回調和異步調用。

同步調用:一種阻塞式調用,調用方要等待對方執行完畢才返回,它是一種單向調用;

回    調:一種雙向調用模式,也就是說,被調用方在接口被呼叫時也會呼叫對方的介面;

非同步呼叫:一種類似訊息或事件的機制,不過它的呼叫方向剛好相反,介面的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即呼叫客戶方的介面)。

回調和非同步呼叫的關係非常緊密:使用回呼來實現非同步訊息的註冊,透過非同步呼叫來實現訊息的通知。

回呼實例

1、回調介面

public interface Callback {
 
   String callBack();
 }

2、呼叫者

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

3、測試回呼函數

reee

的使用過程中。模板方法設計模式就使用方法回呼的機制,該模式首先定義特定的步驟的演算法骨架,而將一些步驟延遲到子類別中去實現的設計模式。模板方法設計模式使得子類別可以不改變一個演算法的結構即可重新定義該演算法的某些特定步驟。

模板方式設計模式的適用性:

  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、獲取connection 

2、獲取statement 
3、取得resultset 

4、遍歷resultset並封裝成集合 

5、依序關閉connection,statement,resultset,而且還要考慮各種例外等等。

如果是多個查詢會產生較多的重複程式碼,這時候就可以使用模板機制,透過觀察我們發現上面步驟中大多數都是重複的,可複用的,只有在遍歷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
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),