posts - 5, comments - 0, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          匿名內部類-回調-閉包

          Posted on 2011-11-24 16:44 火炎炎 閱讀(890) 評論(0)  編輯  收藏

          首先明確閉包的概念:一個代碼段被用來做為方法的參數.
          java中沒有直接使用某個方法做為另一個方法的參數的,java使用匿名內部類來模擬這種情況。

          匿名內部類往往是做為一個內部類(接口)的具體實現。在一些平臺類(platform class)中有一些模板方法。模板方法的包含了固定流程。其中某些步驟是調用了內部類(接口)中的某些方法。但是平臺類將這些方法的具體實現延遲到了業務類中。業務類調用平臺類的模板方法,但是傳入匿名內部類的實現做為模板方法的參數。

          示例:

           

          package callback;

          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.SQLException;

          public class AnonymousBusinessTemplateExample2 {

          // 內部接口也是回調接口,只定義抽象方法。
          private interface Callback {
          Object doIt(Connection conn)
          throws SQLException;
          }

          // 模板方法(抽象)
          private Object execute(Callback callback) throws SQLException {
          Connection conn
          = openConnection();
          try {
          return callback.doIt(conn);
          }
          finally {
          closeConnection(conn);
          }
          }

          // 業務方法(具體)
          public Object sqlQuery(final String sql) throws SQLException {
          //匿名內部類做為模板方法的參數來模擬閉包
          return execute(new Callback() {
          public Object doIt(Connection conn) throws SQLException {
          return conn.createStatement().executeQuery(sql);
          }
          });
          }

          public Connection openConnection() throws SQLException {
          return DriverManager.getConnection("", null);
          }

          public void closeConnection(Connection conn) throws SQLException {
          if (conn != null && !conn.isClosed()) {
          conn.close();
          }
          }
          }

           

           

           

          一般內部接口比內部類用的更多。內部類中的方法可以有默認的實現。匿名內部類做為業務方法的參數傳入時,會override默認的方法。內部接口的話,沒有默認的實現。完全將具體的實現交給了匿名內部類。

          匿名內部類的思想是回調,即好茉塢原則。回調的一個好處是decouple。 客戶端只需要關心業務(比如匿名內部類的具體實現)而不用再關心一些資源的連接釋放什么的,這些交給平臺類中的模板方法。ruby的閉包還支持對數組中的每個元素,文件中的每行,結果集中的每個記錄的操作。而用java實現這樣的迭代并操作其中元素非常麻煩。感覺java中用的多的偏模板方法,即邏輯中固定一些流程,初始化及釋放某些資源。






          動態回調函數、匿名內部類和spring中的excute方法

              公司目前采用了spring框架來構建和管理整個web項目。對于持久層的處理,使用了由spring框架提供的對hibernate3的封裝。這樣做無非是為了使用spring提供的對事務的統一管理。當我們用到由spring所封裝的hibernate的時候一定會用到一個類:HibernateTemplate.這是一個對持久層處理封裝的非常完整的類,包括對session的管理(事實上session的獲取于釋放是一個令人頭疼的問題)等等,我們通常會使用HibernateTemplate的excute方法來進行數據庫操作(即使我們調用的也許是別的類似于find、get之類的方法,但是實質上最終還是轉變為了調用excute方法)。對于第一次使用這個方法一定會存在困擾。因為excute方法所需要的參數一個HibernateCallback類型的參數。而在excute方法體內部回調了HibernateCallback類型的doInHibernate方法。這是一個典型的對象回調。就到目前為止也許一切都很清晰。但是實際上如果閱讀了HibernateTemplate的內部代碼就會發現,對于像get、find這樣的方法最終都回調用excute來完成數據庫操作但是調用形式看起來卻很奇怪:

          public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)

                  throws DataAccessException

              {

                  return execute(new HibernateCallback() {

                      public Object doInHibernate(Session session)

                          throws HibernateException

                      {

                          if(lockMode != null)

                              return session.get(entityClass, id, lockMode);

                          else

                              return session.get(entityClass, id);

                      }

                  }, true);

              }

              Excute方法的參數是一種匿名類的方式。為什么要采用匿名類呢(不管怎么說匿名類看起來總是讓人覺得不舒服)?這個地方是否必須采用匿名類呢?

              首先我們來想一想這段代碼涉及到幾個關鍵點:1、回調:excute方法會回調HibernateCallback類型的doInHibernate方法;2、匿名類參數:我們為excute方法提供的參數并不是一個真正生命出來的HibernateCallback實例。3、動態創建回調方法:如果我們打開HibernateCallback類就會發現,其實這是一個abstract類型的類,而他聲明了唯一的一個ie抽象方法就是doInHibernate。問題似乎已經明朗了,如果不采用匿名類,我們需要做的是為HibernateCallback創建一個實現類,并且實現doInHibernate方法。但是最要命的問題是doInHibernate方法的實現對于我們的實際需求來說每一次調用可能都是不一樣的(在doInHibernate方法中我們使用session進行數據庫操作,對于不同的業務邏輯,方法實現必定是不一樣的),采用了匿名類我們不用在代碼重創建新的類型,而且可以動態的創建我們所需要的回調函數。

              總結一下,我們上面所講的并非是如何使用HibernateTemplate這個類。我們得到的結論是:當我們需要動態的創建回調函數的時候,匿名內部類是一個好的方式。注:這種需要動態創建的回調方法通常是一個interface中的接口或者abstract class中的抽象方法。



          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 昆明市| 望城县| 镶黄旗| 鸡西市| 黄平县| 富裕县| 会东县| 嘉峪关市| 北安市| 砚山县| 湟中县| 容城县| 疏附县| 大城县| 齐齐哈尔市| 池州市| 合肥市| 南丰县| 凤凰县| 奉新县| 读书| 皋兰县| 儋州市| 诸暨市| 措勤县| 深圳市| 兰坪| 治县。| 无棣县| 秦皇岛市| 定日县| 葫芦岛市| 天津市| 宜君县| 阿拉善右旗| 吉安市| 贡嘎县| 勐海县| 西盟| 读书| 皋兰县|