最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

    3、他的調(diào)用時(shí)機(jī)由工作流決定,回調(diào)函數(shù)的實(shí)現(xiàn)者不能直接調(diào)用回調(diào)函數(shù)來(lái)實(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)用模式,也就是說(shuō),被調(diào)用方在接口被調(diào)用時(shí)也會(huì)調(diào)用對(duì)方的接口;

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

回調(diào)和異步調(diào)用的關(guān)系非常緊密:使用回調(diào)來(lái)實(shí)現(xiàn)異步消息的注冊(cè),通過(guò)異步調(diào)用來(lái)實(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í)候,通過(guò)委派,來(lái)調(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接口”和“抽象類”的使用過(guò)程中。模板方法設(shè)計(jì)模式就使用方法回調(diào)的機(jī)制,該模式首先定義特定的步驟的算法骨架,而將一些步驟延遲到子類中去實(shí)現(xiàn)的設(shè)計(jì)模式。模板方法設(shè)計(jì)模式使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重新定義該算法的某些特定步驟。

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

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

  2、各子類中公共的行為應(yīng)該被提取出來(lái)并集中一個(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ì)說(shuō)明模板模式和回調(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)單的查詢,就要做這么一大堆事情,而且還要處理異常,我們不防來(lái)梳理一下:
1、獲取connection
2、獲取statement
3、獲取resultset
4、遍歷resultset并封裝成集合
5、依次關(guān)閉connection,statement,resultset,而且還要考慮各種異常等等。

如果是多個(gè)查詢會(huì)產(chǎn)生較多的重復(fù)代碼,這時(shí)候就可以使用模板機(jī)制,通過(guò)觀察我們發(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來(lái)管理DataSource和轉(zhuǎn)換異常等。

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

相關(guān)文章

  • Spring使用注解方式實(shí)現(xiàn)創(chuàng)建對(duì)象

    Spring使用注解方式實(shí)現(xiàn)創(chuàng)建對(duì)象

    這篇文章主要介紹了Spring使用注解方式實(shí)現(xiàn)創(chuàng)建對(duì)象,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2023-02-02
  • 一篇文章教你使用枚舉來(lái)實(shí)現(xiàn)java單例模式

    一篇文章教你使用枚舉來(lái)實(shí)現(xiàn)java單例模式

    本篇文章主要介紹了Java實(shí)現(xiàn)單例的3種普遍的模式,餓漢式、懶漢式、枚舉式。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來(lái)幫助
    2021-07-07
  • Spring Boot使用Spring的異步線程池的實(shí)現(xiàn)

    Spring Boot使用Spring的異步線程池的實(shí)現(xiàn)

    這篇文章主要介紹了Spring Boot使用Spring的異步線程池的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • IDEA配置jdk環(huán)境變量的方法

    IDEA配置jdk環(huán)境變量的方法

    這篇文章主要介紹了IDEA配置jdk環(huán)境變量的方法,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 詳解spring Boot Cli的配置和使用

    詳解spring Boot Cli的配置和使用

    本篇文章主要介紹了詳解spring Boot Cli的配置和使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • 基于redis setIfAbsent的使用說(shuō)明

    基于redis setIfAbsent的使用說(shuō)明

    這篇文章主要介紹了基于redis setIfAbsent的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • Java設(shè)計(jì)模式之橋接模式詳解(Bridge Pattern)

    Java設(shè)計(jì)模式之橋接模式詳解(Bridge Pattern)

    橋接模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,旨在將抽象部分與其實(shí)現(xiàn)部分分離,從而使兩者可以獨(dú)立地變化,橋接模式通過(guò)組合關(guān)系代替繼承關(guān)系,將抽象和實(shí)現(xiàn)解耦,使代碼更具擴(kuò)展性和維護(hù)性
    2025-02-02
  • java?讀寫?ini?配置文件的示例代碼

    java?讀寫?ini?配置文件的示例代碼

    這篇文章主要介紹了java?讀寫?ini?配置文件,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • 深入理解Java中的類加載器原理

    深入理解Java中的類加載器原理

    這篇文章主要介紹了深入理解Java中的類加載器原理,類加載器負(fù)責(zé)加載所有的類,系統(tǒng)為所有被載入內(nèi)存中的類生成一個(gè)java.lang.Class實(shí)例,需要的朋友可以參考下
    2024-01-01
  • Java中的同步非阻塞IO模型詳解

    Java中的同步非阻塞IO模型詳解

    這篇文章主要介紹了Java中的同步非阻塞IO模型詳解,同步非阻塞IO模型,我們能夠知道,用戶線程一直發(fā)送請(qǐng)求,內(nèi)核一直都能都?jí)蚍祷?nbsp;,直到內(nèi)核完成準(zhǔn)備數(shù)據(jù)、數(shù)據(jù)拷貝的工作,并且返回成功的指示,在此過(guò)程中用戶線程不是阻塞的狀態(tài),需要的朋友可以參考下
    2024-01-01

最新評(píng)論

江山市| 金阳县| 丹东市| 双牌县| 罗源县| 马公市| 清水河县| 永春县| 广丰县| 东兴市| 界首市| 正镶白旗| 马公市| 伊川县| 广平县| 滨州市| 崇左市| 卢龙县| 平和县| 岳阳县| 永登县| 通州区| 南皮县| 奈曼旗| 遵化市| 波密县| 古蔺县| 望城县| 吴桥县| 辽阳县| 石河子市| 井陉县| 永德县| 钟山县| 咸丰县| 阳信县| 包头市| 织金县| 法库县| 衡阳市| 冀州市|