<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 193,  comments - 520,  trackbacks - 0
    關(guān)于Domain Model的討論已經(jīng)非常多了,炒炒冷飯,這里是自己的一些做法。
    以Workitem(工作流里的工作項(xiàng))作為例子

    最開始的做法:
    一個(gè)實(shí)體類叫做Workitem,指的是一個(gè)工作項(xiàng)或者稱為任務(wù)項(xiàng)
    一個(gè)DAO類叫做WorkitemDao
    一個(gè)業(yè)務(wù)邏輯類叫做WorkitemManager(或者叫做WorkitemService)

    主要看看WorkitemManager,因?yàn)橹饕壿嫾性谶@里

    public class WorkitemManager {

            
    private WorkItemDAO workItemDAO;

        
    public void setWorkItemDAO(WorkItemDAO workItemDAO) {
            
    this.workItemDAO = workItemDAO;
        }
        
        
    /**
         * 提交工作項(xiàng)
         * 
    @param workitemId 工作項(xiàng)ID
         
    */
        
    public void commitWorkitem(String workitemId){
                WorkItem workitem 
    = workItemDAO.getWorkItem(workitemId);
                
    //當(dāng)前工作項(xiàng)結(jié)束
            workitem.complete();
            
    int sID = workitem.getSequenceId();
            
    //找到所對應(yīng)的節(jié)點(diǎn)
            InstActivity instActivity=workitem.getInstActivity();
            
    //查找是否存在下一工作項(xiàng)
            WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
            
    //如果不存在則觸發(fā)節(jié)點(diǎn)流轉(zhuǎn)
            if (sequenceWorkitem == null) {
                instActivity.signal();
            }
            
    //否則把下一工作項(xiàng)激活
            else {
                sequenceWorkitem.setExecutive();
            }
        }
        
    }


    Workitem類里有一些狀態(tài)轉(zhuǎn)換的邏輯,這樣避免直接調(diào)用get/set屬性方法

    public class Workitem{

            
    private int state = WorkitemInfo.PREPARE;

            
    /**
         * 委派工作項(xiàng)
         
    */
        
    public void commission() {
            
    if (state != WorkitemInfo.EXECUTE && state != WorkitemInfo.SIGNINED
                    
    && state != WorkitemInfo.TOREAD&& state != WorkitemInfo.SUSPEND)
                
    throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
            setState(WorkitemInfo.COMMISSIONED);
            setCommitted(
    new Timestamp(System.currentTimeMillis()));
        }

        
    /**
         * 完成工作項(xiàng)
         
    */
        
    public void complete() {
            
    if (state != WorkitemInfo.SIGNINED)
                
    throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
            setState(WorkitemInfo.COMPLETE);
            setCompleted(
    new Timestamp(System.currentTimeMillis()));
        }
    }


    接下來的做法:
    三個(gè)類不變,將WorkitemManager打平,將邏輯移動(dòng)到Workitem

    public class WorkitemManager {

            
    private WorkItemDAO workItemDAO;

        
    public void setWorkItemDAO(WorkItemDAO workItemDAO) {
            
    this.workItemDAO = workItemDAO;
        }
        
        
    /**
         * 提交工作項(xiàng)
         * 
    @param workitemId 工作項(xiàng)ID
         
    */
        
    public void commitWorkitem(String workitemId){
                WorkItem workitem 
    = workItemDAO.getWorkItem(workitemId);
                
    //當(dāng)前工作項(xiàng)提交
            workitem.commit();
        }
        
    }

    實(shí)際上此時(shí)WorkitemManager的功能非常有限,僅僅是事務(wù)邊界和獲取workitem對象,甚至在一些情況下可以省略。

    通過一個(gè)Container類將spring的applicationContext進(jìn)行封裝,然后通過getBean()的靜態(tài)方法即可訪問被spring所管理的bean。實(shí)際是將workItemDAO隱式注入了Workitem。

    public class Workitem{

            
    /**
         * 提交工作項(xiàng)
         
    */
        
    public void commit() {
            
    if (state != WorkitemInfo.EXECUTE && state != WorkitemInfo.SIGNINED
                    
    && state != WorkitemInfo.TOREAD&& state != WorkitemInfo.SUSPEND)
                
    throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
            setState(WorkitemInfo.COMMISSIONED);
            setCommitted(
    new Timestamp(System.currentTimeMillis()));
            
    int sID = workitem.getSequenceId();
            WorkItemDAO workItemDAO
    =(WorkItemDAO)Container.getBean("workItemDAO");
            
    //查找是否存在下一工作項(xiàng)
            WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
            
    //如果不存在則觸發(fā)節(jié)點(diǎn)流轉(zhuǎn)
            if (sequenceWorkitem == null) {
                instActivity.signal();
            }
            
    //否則把下一工作項(xiàng)激活
            else {
                sequenceWorkitem.setExecutive();
            }
        }

    }


    這樣帶來的好處是業(yè)務(wù)邏輯全部被封裝到Domain Model,Domain Model之間的交互變得非常的簡單,沒有頻繁的set/get,直接調(diào)用有業(yè)務(wù)語義的Domain Model的方法即可。問題在于單元測試時(shí)脫離不了spring的容器,workItemDAO需要stub。我覺得這個(gè)問題不大,問題是Domain Model開始變得臃腫,在業(yè)務(wù)邏輯復(fù)雜時(shí)代碼行急劇膨脹。

    現(xiàn)在的做法
    以上三個(gè)類保持不變,增加一個(gè)類WorkitemExecutor,將業(yè)務(wù)邏輯移步。

    public class Workitem{

            
    /**
         * 提交工作項(xiàng)
         
    */
        
    public void commit() {
            
    if (state != WorkitemInfo.EXECUTE && state != WorkitemInfo.SIGNINED
                    
    && state != WorkitemInfo.TOREAD&& state != WorkitemInfo.SUSPEND)
                
    throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
            setState(WorkitemInfo.COMMISSIONED);
            setCommitted(
    new Timestamp(System.currentTimeMillis()));
            WorkitemExecutor workitemExecutor
    =(WorkitemExecutor)Container.getBean("workitemExecutor");
            workitemExecutor.commitWorkitem(
    this);
        }

    }

    public class WorkitemExecutor {

            
    private WorkItemDAO workItemDAO;

        
    public void setWorkItemDAO(WorkItemDAO workItemDAO) {
            
    this.workItemDAO = workItemDAO;
        }
        
        
    /**
         * 提交工作項(xiàng)
         * 
    @param workitemId 工作項(xiàng)ID
         
    */
        
    public void commitWorkitem(Workitem workitem){
            
    int sID = workitem.getSequenceId();
            
    //找到所對應(yīng)的節(jié)點(diǎn)
            InstActivity instActivity=workitem.getInstActivity();
            
    //查找是否存在下一工作項(xiàng)
            WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
            
    //如果不存在則觸發(fā)節(jié)點(diǎn)流轉(zhuǎn)
            if (sequenceWorkitem == null) {
                instActivity.signal();
            }
            
    //否則把下一工作項(xiàng)激活
            else {
                sequenceWorkitem.setExecutive();
            }
        }
        
    }


    將業(yè)務(wù)邏輯拆分成兩部分,一部分在Workitem,另一部分委托給WorkitemExecutor。實(shí)際上是Domain Model將復(fù)雜邏輯的情況重新外包出去。調(diào)用的時(shí)候,面向的接口還是Domain Model的方法。注意到WorkitemExecutor和WorkitemManager的API是非常相似的。實(shí)際可以這樣認(rèn)為,傳統(tǒng)的方式
    Client->(Business Facade)->service(Business Logic 部分依賴Domain Model)->Data Access(DAO)。
    現(xiàn)在的方式
    Client->(Business Facade)->Domain Model->service->Data Access(DAO)。

    另外,在返回client端的查詢的時(shí)候還是傾向于直接調(diào)用DAO,而不是通過Domain Model。

    改進(jìn):
    注意到代碼中有這么一行
    WorkItemDAO workItemDAO=(WorkItemDAO)Container.getBean("workItemDAO");

    確實(shí)是一個(gè)bad smell.當(dāng)代碼中大量出現(xiàn)后,這種造型是很恐怖的。所以采取了一種處理方式:給所有Domain Model繼承一個(gè)父類,在父類里集中管理所有Domain Model所依賴的services,在父類里進(jìn)行造型。




    http://m.tkk7.com/ronghao 榮浩原創(chuàng),轉(zhuǎn)載請注明出處:)
    posted on 2008-07-03 18:23 ronghao 閱讀(2617) 評論(2)  編輯  收藏 所屬分類: 工作日志

    FeedBack:
    # re: 從貧血到充血Domain Model
    2011-03-14 09:04 | 人在江湖
    請教,有句沒看懂
    WorkItemDAO workItemDAO=(WorkItemDAO)Container.getBean("workItemDAO");
    這個(gè)為什么不是注射進(jìn)來的呢?

    覺得你“接下來的做法”和“現(xiàn)在的做法”沒啥區(qū)別啊,呵呵,就是沒有封裝private方法,而是單弄了類。

    張小慶的故事挺好的,不希望故事結(jié)局太灰暗。樓主牛人,給程序員們些念想吧,呵呵。  回復(fù)  更多評論
      
    # re: 從貧血到充血Domain Model[未登錄]
    2011-03-14 18:33 | ronghao
    @人在江湖
    無法注入,WorkItem是不受容器管理的。
    謝謝關(guān)注張小慶!  回復(fù)  更多評論
      
    <2008年7月>
    293012345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    關(guān)注工作流和企業(yè)業(yè)務(wù)流程改進(jìn)。現(xiàn)就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

    常用鏈接

    留言簿(38)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    常去的網(wǎng)站

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲精品美女久久久久99| 97在线观看永久免费视频| 一个人看www免费高清字幕| 国产亚洲情侣久久精品| 国产成人精品亚洲一区| 蜜桃传媒一区二区亚洲AV| 亚洲精品乱码久久久久蜜桃| 亚洲国产精品无码久久98| 国产区图片区小说区亚洲区| 国产亚洲成在线播放va| 91av免费在线视频| 成人A毛片免费观看网站| a级毛片在线视频免费观看| 国产精品免费看久久久 | 亚洲嫩模在线观看| 亚洲成人激情在线| 亚洲成aⅴ人在线观看| 国产亚洲玖玖玖在线观看| 成人婷婷网色偷偷亚洲男人的天堂| 色欲aⅴ亚洲情无码AV| 久久国产乱子伦精品免费午夜| 两个人日本免费完整版在线观看1| 久久国产精品国产自线拍免费| www视频免费看| 女性无套免费网站在线看| 亚洲国产黄在线观看| 亚洲乱亚洲乱妇无码麻豆| 亚洲视频一区调教| 亚洲乱码一二三四区乱码| 精品亚洲国产成人av| 国产免费人成视频在线播放播 | 无套内谢孕妇毛片免费看看| 国产黄色免费观看| 84pao强力永久免费高清| 99在线视频免费观看视频| 又粗又硬免费毛片| 亚洲精品亚洲人成在线观看| 亚洲福利秒拍一区二区| 亚洲av永久无码精品秋霞电影秋 | 97在线视频免费公开观看| 精品剧情v国产在免费线观看|