posts - 14,  comments - 37,  trackbacks - 0
          CallBack在EJb3 spec中不過(guò)是一小章節(jié),似乎不是很引人注意,剛開(kāi)始,也沒(méi)有引起我們的多少注意, 然而,在開(kāi)發(fā)中,當(dāng)我們實(shí)際運(yùn)用它來(lái)解決問(wèn)題的時(shí)候,發(fā)現(xiàn)它的實(shí)際作用還是很大的。 其實(shí),從根本來(lái)說(shuō),CallBack相當(dāng)于ORM Engine和用戶設(shè)計(jì)的Domain Model(可持久話的模型) 之間一道天然的鉤子,通過(guò)它,設(shè)計(jì)者可以放入很多類(lèi)似橫切面的關(guān)注點(diǎn)。 下面給出一個(gè)真實(shí)的例子:
          銀行需要對(duì)涉及帳務(wù)每一個(gè)操作實(shí)行錄入,復(fù)核機(jī)制。假設(shè)操作涉及實(shí)體有Customer,Account。 錄入紀(jì)錄實(shí)體為InputRecord, 復(fù)核紀(jì)錄為:ConfirmRecord.用戶為User。
          初步設(shè)計(jì)時(shí),這些類(lèi)的骨干代碼為:
                  @Entity
          class User{
          @Id
          long id=-1;
          String userName;
          String passwordHex;
          }
          @Entity
          class Customer{
          @Id
          long id=-1;
          String name;
          @OneToOne
          InputRecord inputRecord;
          @OneToOne
          ConfirmRecord confirmRecord;
          }
          @Entity
          class Account{
          @Id
          long id=-1;
          String accountName;
          String accountNo;
          @OneToOne
          InputRecord inputRecord;
          @OneToOne
          ConfirmRecord confirmRecord;
          }
          //Not a persistence Entity
          abstract class OperationRecord{
          @Id
          long id=-1;
          @ManyToOne
          User user;
          Date date;
          }
          @Entity
          class InputRecord extends OperationRecord{
          //nothing ,just define a concrete class and table
          }
          @Entity
          class ConfirmRecord extends OperationRecord{
          //nothing ,just define a concrete class and table
          }
          
          上面這段代碼有幾點(diǎn)需要說(shuō)明一下:
          1) OperationRecord沒(méi)有聲明為Entity,這里沒(méi)有用到繼承策略,因?yàn)閷?duì)象繼承與數(shù)據(jù)庫(kù)之間的映射并不是很好,在一般設(shè)計(jì)中,我是很少使用它的,繼承和數(shù)據(jù)共享兩者是沒(méi)有什么關(guān)聯(lián)的, 因?yàn)樵趦?nèi)存中,他們的實(shí)例始終是互補(bǔ)相干的數(shù)據(jù)副本,單純從數(shù)據(jù)來(lái)說(shuō),分別對(duì)應(yīng)到不同的表中來(lái)存儲(chǔ)就是最好的映射,而行為的繼承在JVM中可以得到完全的體現(xiàn)。基于這個(gè)認(rèn)識(shí),InputRecord,ConfirmRecord僅僅起表明類(lèi)型的作用。
          2)從Account,Customer的代碼中可以看出InputRecord,ConfirmRecord域是重復(fù)出現(xiàn)的,而且從需求來(lái)看,會(huì)有更多的實(shí)體需要這兩個(gè)Field,從1)的分析中,很自然而然的抽取一個(gè)基類(lèi)出來(lái):

              abstract class ConfirmableEntity{
          @OneToOne
          InputRecord inputRecord;
          @OneToOne
          ConfirmRecord confirmRecord;
          }
          class Customer extends ConfirmableEntity{
          }
          


          到這里,一個(gè)對(duì)需求的思考同時(shí)也出現(xiàn)了,在什么地方紀(jì)錄操作記錄呢? AOP? TemplateMethod? 很多種可選的方案。然而,從代碼量和簡(jiǎn)潔性來(lái)說(shuō),CallBack是好的。采用CallBack的基本骨干代碼如下:

              abstract class ConfirmableEntity{
          @PostPersist
          public void registerInputRecord(){
          //retrieve current user
          User currentUser = UserHolder.getCurrentUser();
          //create an inputRecord for current User
          InputRecord inputRec = new InputRecord(currentUser);
          setInputRecord(inputRec);
          }
          }
          

          所有的需要錄入復(fù)核得實(shí)體只要繼承自這個(gè)ConfirmableEntity,不僅獲得數(shù)據(jù),同樣獲得了相應(yīng)的行為。這么一段代碼對(duì)于他們來(lái)說(shuō)基本上時(shí)透明的。(有點(diǎn)類(lèi)似AOP? )上面的代碼中,UserHolder是一個(gè)非常有意思的設(shè)計(jì),用戶的保持一般有不同的需求,在Web中有Session,而在別的應(yīng)用中就不一定使用這樣的機(jī)制了,但不管如何,我們總歸有在領(lǐng)域?qū)犹岢霁@取當(dāng)前操作用戶的需求,一個(gè)很簡(jiǎn)單的設(shè)計(jì)會(huì)讓很多事情變得簡(jiǎn)單,可以把UserHolder當(dāng)作一個(gè)隔離領(lǐng)域?qū)雍途唧wApp層用戶管理的接口,大家如果對(duì)它得出現(xiàn)比較有詫異的話可以再具體討論一下.

          值得一說(shuō)的是,這樣的設(shè)計(jì)對(duì)于以后的可擴(kuò)展也帶來(lái)了巨大的影響,比如,用戶提出需求:對(duì)于已經(jīng)復(fù)核得操作紀(jì)錄不能再被修改,刪除。那么我們只要再在ConfirmableEntity上寫(xiě)一個(gè)CallBack即可:
              abstract class ConfirmableEntity{
          @PostPersist
          public void registerInputRecord(){
          //retrieve current user
          User currentUser = UserHolder.getCurrentUser();
          //create an inputRecord for current User
          InputRecord inputRec = new InputRecord(currentUser);
          setInputRecord(inputRec);
          }
          @PreUpdate
          @PreRemove
          public void check(){
          if(getConfirmRecord()!=null && getConfirmRecord().getId()>0 )
          throw new SecurityException("can not update/remove confirmed record");
          }
          }
          
          posted on 2007-07-30 11:20 冰封的愛(ài) 閱讀(361) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): J2EE
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          留言簿(3)

          隨筆檔案

          文章分類(lèi)

          文章檔案

          相冊(cè)

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 泸溪县| 六安市| 河池市| 隆昌县| 卢湾区| 陆丰市| 昌吉市| 龙泉市| 阳新县| 白玉县| 连南| 罗城| 华坪县| 比如县| 铜川市| 奉节县| 贡觉县| 临高县| 怀集县| 苍溪县| 招远市| 南召县| 肇源县| 井陉县| 茂名市| 沈阳市| 泽普县| 孟津县| 子长县| 胶州市| 延安市| 竹溪县| 玛沁县| 莱州市| 天柱县| 贡觉县| 伊吾县| 英超| 漳浦县| 鹰潭市| 平和县|