欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解java模板和回調(diào)機(jī)制

 更新時(shí)間:2016年03月06日 15:03:04   作者:ngulc  
這篇文章主要為大家詳細(xì)介紹了java模板和回調(diào)機(jī)制,學(xué)習(xí)java模板,感興趣的朋友可以參考一下

最近看spring的JDBCTemplete的模板方式調(diào)用時(shí),對(duì)模板和回調(diào)產(chǎn)生了濃厚興趣,查詢了一些資料,做一些總結(jié)。

回調(diào)函數(shù):

  所謂回調(diào),就是客戶程序C調(diào)用服務(wù)程序S中的某個(gè)函數(shù)A,然后S又在某個(gè)時(shí)候反過來調(diào)用C中的某個(gè)函數(shù)B,對(duì)于C來說,這個(gè)B便叫做回調(diào)函數(shù)?;卣{(diào)函數(shù)只是一個(gè)功能片段,由用戶按照回調(diào)函數(shù)調(diào)用約定來實(shí)現(xiàn)的一個(gè)函數(shù)?;卣{(diào)函數(shù)是一個(gè)工作流的一部分,由工作流來決定函數(shù)的調(diào)用(回調(diào))時(shí)機(jī)。一般說來,C不會(huì)自己調(diào)用B,C提供B的目的就是讓S來調(diào)用它,而且是C不得不提供。由于S并不知道C提供的B姓甚名誰,所以S會(huì)約定B的接口規(guī)范(函數(shù)原型),然后由C提前通過S的一個(gè)函數(shù)R告訴S自己將要使用B函數(shù),這個(gè)過程稱為回調(diào)函數(shù)的注冊(cè),R稱為注冊(cè)函數(shù)。Web Service以及Java 的RMI都用到回調(diào)機(jī)制,可以訪問遠(yuǎn)程服務(wù)器程序?;卣{(diào)函數(shù)包含下面幾個(gè)特性:

    1、屬于工作流的一個(gè)部分;

    2、必須按照工作流指定的調(diào)用約定來申明(定義);

    3、他的調(diào)用時(shí)機(jī)由工作流決定,回調(diào)函數(shù)的實(shí)現(xiàn)者不能直接調(diào)用回調(diào)函數(shù)來實(shí)現(xiàn)工作流的功能; 

回調(diào)機(jī)制:

回調(diào)機(jī)制是一種常見的設(shè)計(jì)模型,他把工作流內(nèi)的某個(gè)功能,按照約定的接口暴露給外部使用者,為外部使用者提供數(shù)據(jù),或要求外部使用者提供數(shù)據(jù)。

java回調(diào)機(jī)制:

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

同步調(diào)用:一種阻塞式調(diào)用,調(diào)用方要等待對(duì)方執(zhí)行完畢才返回,它是一種單向調(diào)用;

回    調(diào):一種雙向調(diào)用模式,也就是說,被調(diào)用方在接口被調(diào)用時(shí)也會(huì)調(diào)用對(duì)方的接口;

異步調(diào)用:一種類似消息或事件的機(jī)制,不過它的調(diào)用方向剛好相反,接口的服務(wù)在收到某種訊息或發(fā)生某種事件時(shí),會(huì)主動(dòng)通知客戶方(即調(diào)用客戶方的接口)。

回調(diào)和異步調(diào)用的關(guān)系非常緊密:使用回調(diào)來實(shí)現(xiàn)異步消息的注冊(cè),通過異步調(diào)用來實(shí)現(xiàn)消息的通知。

回調(diào)實(shí)例

1、回調(diào)接口

public interface Callback {

   String callBack();
 }

2、調(diào)用者

public class Another {
  private Callback callback;
  //調(diào)用實(shí)現(xiàn)類的方法
  public void setCallback(Callback callback) {
    this.callback = callback;
  }
    //業(yè)務(wù)需要的時(shí)候,通過委派,來調(diào)用實(shí)現(xiàn)類的具體方法
  public void doCallback(){
    System.out.println(callback.callBack());
  }
}

3、測(cè)試回調(diào)函數(shù)

public class TestCallcack {
  public static void main(String[] args) {
    //創(chuàng)建調(diào)用者的實(shí)現(xiàn)類
    Another another = new Another();
    //將回掉接口注冊(cè)到實(shí)現(xiàn)類中
    another.setCallback(new Callback() {  
      @Override
      public String callBack() {
        return "you are a pig";
      }
    });
    //執(zhí)行回調(diào)函數(shù)
    another.doCallback();
  }
}

回調(diào)方法的使用通常發(fā)生在“java接口”和“抽象類”的使用過程中。模板方法設(shè)計(jì)模式就使用方法回調(diào)的機(jī)制,該模式首先定義特定的步驟的算法骨架,而將一些步驟延遲到子類中去實(shí)現(xiàn)的設(shè)計(jì)模式。模板方法設(shè)計(jì)模式使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重新定義該算法的某些特定步驟。

模板方式設(shè)計(jì)模式的適用性:

  1、一次性實(shí)現(xiàn)一個(gè)算法的不變部分,并將可變的算法留給子類來實(shí)現(xiàn)。

  2、各子類中公共的行為應(yīng)該被提取出來并集中一個(gè)公共父類中以避免代碼重復(fù)。

  3、可以控制子類擴(kuò)展。

模板實(shí)例:

抽象模板方法類:

public abstract class AbstractSup {
    //需要子類實(shí)現(xiàn)的方法
  public abstract void print();
    //模板方法
  public void doPrint(){
    System.out.println("執(zhí)行模板方法");
    for (int i = 0; i < 3; i++) {
      print();
    }
  }
}

子類實(shí)現(xiàn)模板方式類:

public class SubClass extends AbstractSup{
  @Override
  public void print() {
    System.out.println("子類的實(shí)現(xiàn)方法");
  }

}

模板方法測(cè)試類:

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

下面深入介紹下spring模板方法的使用,以JdbcTemplete為例,詳細(xì)說明模板模式和回調(diào)機(jī)制的使用。
首先看一下經(jīng)典的JDBC編程的例子:

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; 
}


一個(gè)簡(jiǎn)單的查詢,就要做這么一大堆事情,而且還要處理異常,我們不防來梳理一下:
1、獲取connection
2、獲取statement
3、獲取resultset
4、遍歷resultset并封裝成集合
5、依次關(guān)閉connection,statement,resultset,而且還要考慮各種異常等等。

如果是多個(gè)查詢會(huì)產(chǎn)生較多的重復(fù)代碼,這時(shí)候就可以使用模板機(jī)制,通過觀察我們發(fā)現(xiàn)上面步驟中大多數(shù)都是重復(fù)的,可復(fù)用的,只有在遍歷ResultSet并封裝成集合的這一步驟是可定制的,因?yàn)槊繌埍矶加成洳煌膉ava bean。這部分代碼是沒有辦法復(fù)用的,只能定制。

抽象類代碼:

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);//抽象方法(定制方法,需要子類實(shí)現(xiàn))  
      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); 
}

這個(gè)抽象類中,封裝了SUN JDBC API的主要流程,而遍歷ResultSet這一步驟則放到抽象方法doInStatement()中,由子類負(fù)責(zé)實(shí)現(xiàn)。

子類實(shí)現(xiàn)代碼:

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; 
    } 
  } 
 
}

我們?cè)赿oInStatement()方法中,對(duì)ResultSet進(jìn)行了遍歷,最后并返回。

測(cè)試代碼:

String sql = "select * from User"; 
JdbcTemplate jt = new JdbcTemplateUserImpl(); 
List<User> userList = (List<User>) jt.execute(sql); 

模板機(jī)制的使用到此為止,但是如果每次調(diào)用jdbcTemplate時(shí),都要繼承一下上面的父類,這樣挺不方便的,這樣回調(diào)機(jī)制就可以發(fā)揮作用了。 

所謂回調(diào),就是方法參數(shù)中傳遞一個(gè)接口,父類在調(diào)用此方法時(shí),必須調(diào)用方法中傳遞的接口的實(shí)現(xiàn)類。

回調(diào)加模板模式實(shí)現(xiàn)

回調(diào)接口:

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);//回調(diào)方法
      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); 
  } 
}

測(cè)試的類:

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不用傳統(tǒng)的模板方法,而加之以Callback進(jìn)行配合呢?
試想,如果父類中有10個(gè)抽象方法,而繼承它的所有子類則要將這10個(gè)抽象方法全部實(shí)現(xiàn),子類顯得非常臃腫。而有時(shí)候某個(gè)子類只需要定制父類中的某一個(gè)方法該怎么辦呢?這個(gè)時(shí)候就要用到Callback回調(diào)了。

另外,上面這種方式基本上實(shí)現(xiàn)了模板方法+回調(diào)模式。但離spring的jdbcTemplate還有些距離。 我們上面雖然實(shí)現(xiàn)了模板方法+回調(diào)模式,但相對(duì)于Spring的JdbcTemplate則顯得有些“丑陋”。Spring引入了RowMapper和ResultSetExtractor的概念。 RowMapper接口負(fù)責(zé)處理某一行的數(shù)據(jù),例如,我們可以在mapRow方法里對(duì)某一行記錄進(jìn)行操作,或封裝成entity。 ResultSetExtractor是數(shù)據(jù)集抽取器,負(fù)責(zé)遍歷ResultSet并根據(jù)RowMapper里的規(guī)則對(duì)數(shù)據(jù)進(jìn)行處理。 RowMapper和ResultSetExtractor區(qū)別是,RowMapper是處理某一行數(shù)據(jù),返回一個(gè)實(shí)體對(duì)象。而ResultSetExtractor是處理一個(gè)數(shù)據(jù)集合,返回一個(gè)對(duì)象集合。

  當(dāng)然,上面所述僅僅是Spring JdbcTemplte實(shí)現(xiàn)的基本原理,Spring JdbcTemplate內(nèi)部還做了更多的事情,比如,把所有的基本操作都封裝到JdbcOperations接口內(nèi),以及采用JdbcAccessor來管理DataSource和轉(zhuǎn)換異常等。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • Java進(jìn)階核心之InputStream流深入講解

    Java進(jìn)階核心之InputStream流深入講解

    這篇文章主要給大家介紹了關(guān)于Java進(jìn)階核心之InputStream流的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Java遍歷Json的簡(jiǎn)單實(shí)例

    Java遍歷Json的簡(jiǎn)單實(shí)例

    這篇文章主要介紹了Java遍歷Json的簡(jiǎn)單實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • maven 指定version不生效的問題

    maven 指定version不生效的問題

    這篇文章主要介紹了maven 指定version不生效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java mybatis框架實(shí)現(xiàn)多表關(guān)系查詢功能

    java mybatis框架實(shí)現(xiàn)多表關(guān)系查詢功能

    這篇文章主要介紹了java mybatis框架實(shí)現(xiàn)多表關(guān)系查詢,基于Maven框架的整體設(shè)計(jì) —— 一多一的關(guān)系,文中通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • IDEA 2020.1 for Mac 下載安裝配置及出現(xiàn)的問題小結(jié)

    IDEA 2020.1 for Mac 下載安裝配置及出現(xiàn)的問題小結(jié)

    這篇文章主要介紹了IDEA 2020.1 for Mac 下載安裝配置及出現(xiàn)的問題小結(jié),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Spring框架 XML配置事務(wù)控制的步驟操作

    Spring框架 XML配置事務(wù)控制的步驟操作

    這篇文章主要介紹了Spring框架 XML配置事務(wù)控制的步驟操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 如何修改maven默認(rèn)的JDK版本

    如何修改maven默認(rèn)的JDK版本

    這篇文章主要介紹了如何修改maven默認(rèn)的JDK版本,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 配置javaw.exe雙擊運(yùn)行jar包方式

    配置javaw.exe雙擊運(yùn)行jar包方式

    這篇文章主要介紹了配置javaw.exe雙擊運(yùn)行jar包方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Nacos源碼之注冊(cè)中心的實(shí)現(xiàn)詳解

    Nacos源碼之注冊(cè)中心的實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了Nacos源碼之注冊(cè)中心的實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Mybatis使用collection標(biāo)簽進(jìn)行樹形結(jié)構(gòu)數(shù)據(jù)查詢時(shí)攜帶外部參數(shù)查詢

    Mybatis使用collection標(biāo)簽進(jìn)行樹形結(jié)構(gòu)數(shù)據(jù)查詢時(shí)攜帶外部參數(shù)查詢

    這篇文章主要介紹了Mybatis使用collection標(biāo)簽進(jìn)行樹形結(jié)構(gòu)數(shù)據(jù)查詢時(shí)攜帶外部參數(shù)查詢,需要的朋友可以參考下
    2023-10-10

最新評(píng)論