<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
    關于Domain Model的討論已經非常多了,炒炒冷飯,這里是自己的一些做法。
    以Workitem(工作流里的工作項)作為例子

    最開始的做法:
    一個實體類叫做Workitem,指的是一個工作項或者稱為任務項
    一個DAO類叫做WorkitemDao
    一個業務邏輯類叫做WorkitemManager(或者叫做WorkitemService)

    主要看看WorkitemManager,因為主要邏輯集中在這里

    public class WorkitemManager {

            
    private WorkItemDAO workItemDAO;

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


    Workitem類里有一些狀態轉換的邏輯,這樣避免直接調用get/set屬性方法

    public class Workitem{

            
    private int state = WorkitemInfo.PREPARE;

            
    /**
         * 委派工作項
         
    */
        
    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()));
        }

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


    接下來的做法:
    三個類不變,將WorkitemManager打平,將邏輯移動到Workitem

    public class WorkitemManager {

            
    private WorkItemDAO workItemDAO;

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

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

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

    public class Workitem{

            
    /**
         * 提交工作項
         
    */
        
    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");
            
    //查找是否存在下一工作項
            WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
            
    //如果不存在則觸發節點流轉
            if (sequenceWorkitem == null) {
                instActivity.signal();
            }
            
    //否則把下一工作項激活
            else {
                sequenceWorkitem.setExecutive();
            }
        }

    }


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

    現在的做法
    以上三個類保持不變,增加一個類WorkitemExecutor,將業務邏輯移步。

    public class Workitem{

            
    /**
         * 提交工作項
         
    */
        
    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;
        }
        
        
    /**
         * 提交工作項
         * 
    @param workitemId 工作項ID
         
    */
        
    public void commitWorkitem(Workitem workitem){
            
    int sID = workitem.getSequenceId();
            
    //找到所對應的節點
            InstActivity instActivity=workitem.getInstActivity();
            
    //查找是否存在下一工作項
            WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
            
    //如果不存在則觸發節點流轉
            if (sequenceWorkitem == null) {
                instActivity.signal();
            }
            
    //否則把下一工作項激活
            else {
                sequenceWorkitem.setExecutive();
            }
        }
        
    }


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

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

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

    確實是一個bad smell.當代碼中大量出現后,這種造型是很恐怖的。所以采取了一種處理方式:給所有Domain Model繼承一個父類,在父類里集中管理所有Domain Model所依賴的services,在父類里進行造型。




    http://m.tkk7.com/ronghao 榮浩原創,轉載請注明出處:)
    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");
    這個為什么不是注射進來的呢?

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

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

    關注工作流和企業業務流程改進。現就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

    常用鏈接

    留言簿(38)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    常去的網站

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 日韩va亚洲va欧洲va国产| 国产亚洲大尺度无码无码专线 | 亚洲狠狠婷婷综合久久蜜芽| 91香蕉国产线观看免费全集| 中文字幕日本人妻久久久免费| 亚洲精品无码久久毛片| 一级美国片免费看| 在线精品亚洲一区二区小说| 国产美女视频免费观看的网站 | 中文字幕无线码中文字幕免费 | 亚洲色图视频在线观看| 精品国产无限资源免费观看| 亚洲国产精品网站久久| 久久嫩草影院免费看夜色| 国产亚洲精品线观看动态图| 免费网站观看WWW在线观看| 老色鬼久久亚洲AV综合| 67194熟妇在线永久免费观看| 亚洲中文字幕无码中文| 日本免费中文字幕在线看| 久久av免费天堂小草播放| 亚洲国产成人片在线观看无码| 日韩精品无码一区二区三区免费| 亚洲国产精品线观看不卡| 日韩成人在线免费视频 | a级在线观看免费| 亚洲综合免费视频| 日韩高清免费在线观看| 99视频免费在线观看| 亚洲精品中文字幕无乱码| 日韩电影免费在线| 在线观看免费视频网站色| 亚洲人成网站18禁止久久影院| 日本一道综合久久aⅴ免费| 黄视频在线观看免费| 亚洲另类精品xxxx人妖| 亚洲黄黄黄网站在线观看| 18女人腿打开无遮掩免费| 三年片在线观看免费观看大全中国 | 一级一级毛片免费播放| 亚洲综合久久成人69|