J2EE之巔

           

          懶對象加載模式

           

          問題

          隨著輕量級持久化框架的流行(如:HibernateJDOJPA),領域對象取代了傳統的DTO直接作為值對象,而在這種架構應用的開發過程中,開發人員常會預見這樣的異常LazyInitializationException。上述問題是由于Hibernate對于領域對象的關系域對象采取了懶加載策略所導致的(即在關系域被訪問時才真正加載創建這些相關對象,Hibernate提供的懶加載策略在很多時候都可以讓我的程序獲得更高的效率);由于領域對象在脫管的狀態下被作為值對象傳回顯示層,而顯示層如果訪問了采用懶加載策略加載的關系域,便會導致LazyInitializationException異常。

          為了避免這個問題,我們常常會在Façade層的業務方法中加入與特定顯示要求相綁定的返回對象初始化過程(即裝載那些被懶加載了的關系域對象)。Façade通常是我們用于控制事務邊界和完成返回的領域對象脫鉤的地方。

          1 表現層是易變的這樣就會導致連鎖反應,大量的代碼需要維護,完全違背了面向對象設計的原則,增加了程序的維護成本。

          2 并且Façade可能用于支持多種不同的表現層,很難讓一個方法滿足不同的要求。

          OSIVOpen Session in View)結構是一種解決上述問題的方法,這種結構之所以能解決上述問題關鍵就在于OSIV在表現層中控制Session的打開和關閉,控制事務邊界。OSIV雖然簡化了應用程序的結構,也避免了LazyInitializationException問題,但是也有很多不足:1.增加了表示層的負責度,2.在響應返回表示層前必須提交事務。3.由于減少了封裝層次,表現層直接操作領域對象使得包括性能方面的各種優化更為困難。

          解決方案

          思考既然表示層知道要顯示的信息,即領域對象應該加載哪些相關聯的對象。那么我們何不把這個任務交給Façade的調用者(表現層)來完成呢?

          不同的表示層可能會有不同的顯示策略,利用策略模式(GoF)我們讓表示層來注入所需的關系域加載策略實現。

          下面便是這個想法的實現:

          示例中的領域模型:


          圖表
          1示例中領域對象模型

          示例中相關的組件


          圖表
          2示例相關組件

          LazyObjectLoader:懶對象加載者接口,其定義如下

          來對象加載策略接口

          package org.ccsoft;

          publicinterface LazyObjectLoader {

              publicvoid loadLazyObjects(Object obj);

          }

          該接口定義了不同懶對象加載策略實現者要實現的方法,在loadLazyObjects方法中實現對領域對象obj相關的關系域對象進行加載的策略。

          OrderItemLoader一種加載策略的實現,用于加載Order對象的關系域對象OrderItem對象

          package org.ccsoft;

          import java.io.Serializable;

          publicclass OrderItem implements Serializable {

             

              private String detail;

              public String getDetail() {

                 returndetail;

              }

              publicvoid setDetail(String detail) {

                 this.detail = detail;

              }

             

          }

          OrderMgrFacadeImp: Façade的實現,可以使POJO也可以使Session Bean

          package org.ccsoft;

          publicclass OrderMgrFacadeImp implements OrderMgrFacade {

              private OrderDAO orderDAO;

              public OrderDAO getOrderDAO() {

                 returnorderDAO;

              }

              publicvoid setOrderDAO(OrderDAO orderDAO) {

                 this.orderDAO = orderDAO;

              }

              public Order getOrder(int orderId, LazyObjectLoader loader) {

                 Order order=orderDAO.getOrder(orderId);

                 loader.loadLazyObjects(order);

                 return order;

              }

             

          }

          getOrder方法中我們要求調用者提供了懶對象裝載策略的實例用于裝載那些調用者要用到的關系域對象。注意該示例是通過spring實現的,利用spring AOP完成事務管理,事務的邊界在Façade中方法上,當方法執行結束,事務業務將結束,并且Hibernate會自動關閉session,我們看到getOrder方法中在事務結束前調用了懶對象裝載策略,從而按照調用者的要求裝載了調用者所需的關系域對象。

          該模式的優點

          1 將領域對象的處理邏輯與顯示層的顯示邏輯完全分離,提高了代碼的可維護性和可擴展性

          該模式的不足

          1 要求顯示層的開發者,了解懶加載的情況

          2 增加了代碼的復雜性

          ________________________________________________________________________

          SCEA SCBCD MCSD
          IBM Certified Specialist RUP
          IBM Certified Solution Designer OOA&D UML v2
          北京天融信軟件架構師
          SUN,Microsoft培訓中心特邀高端教師
          常年提供架構咨詢服務
          chaocai2001@yahoo.com.cn 010-82776427



          posted on 2007-09-20 21:28 超越巔峰 閱讀(1542) 評論(1)  編輯  收藏

          評論

          # re: 懶對象加載模式 2007-09-20 22:41 千里冰封

          這不失為一種好方法:)  回復  更多評論   


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


          網站導航:
           

          導航

          統計

          常用鏈接

          留言簿(12)

          隨筆分類(54)

          隨筆檔案(59)

          文章分類(2)

          文章檔案(1)

          相冊

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 阜阳市| 柏乡县| 洪湖市| 车险| 林芝县| 台前县| 嘉义县| 临江市| 渭源县| 新民市| 昭苏县| 九江市| 永定县| 宜宾县| 延安市| 新绛县| 庐江县| 滨海县| 抚远县| 乌拉特中旗| 措美县| 从江县| 龙里县| 阳山县| 龙海市| 兴和县| 贡山| 南岸区| 永安市| 乐亭县| 彝良县| 福贡县| 稷山县| 弋阳县| 青铜峡市| 登封市| 奉贤区| 浪卡子县| 盘锦市| 瑞金市| 新兴县|