<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://www.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是不受容器管理的。
    謝謝關注張小慶!  回復  更多評論
      
    <2011年3月>
    272812345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

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

    常用鏈接

    留言簿(38)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    常去的網站

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: av成人免费电影| 国产jizzjizz免费视频| 香蕉视频免费在线播放| 亚洲毛片基地4455ww| 亚洲国产另类久久久精品小说| 在线观看免费亚洲| 国产成人午夜精品免费视频| 久久99精品免费视频| 韩国免费A级毛片久久| 男女猛烈无遮掩视频免费软件 | 亚洲国产精品成人网址天堂| 猫咪社区免费资源在线观看| 最近免费最新高清中文字幕韩国| 国精产品一区一区三区免费视频| 一级毛片成人免费看a| 伊人久久国产免费观看视频| 黄色毛片免费观看| 国产精品免费福利久久| 免费污视频在线观看| 久久精品无码精品免费专区| 色窝窝免费一区二区三区| 日本中文一区二区三区亚洲| 免费午夜爽爽爽WWW视频十八禁| 日韩免费a级在线观看| 亚洲色偷拍另类无码专区| 亚洲人成伊人成综合网久久久 | 亚洲精品日韩专区silk| 噜噜噜亚洲色成人网站∨| 亚洲美女视频一区| 老外毛片免费视频播放| **真实毛片免费观看| 国内精品免费麻豆网站91麻豆 | 一级毛片免费观看不卡视频 | 毛片免费全部播放无码| 亚洲av无码专区在线观看素人| 亚洲男人的天堂在线播放| 亚洲高清不卡视频| 一级黄色免费网站| 国产乱码免费卡1卡二卡3卡| 亚洲精品无码高潮喷水在线| 亚洲国产美女精品久久久|