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

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

    常用鏈接

    留言簿(38)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    常去的網站

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲一区二区三区在线播放 | 亚洲一区中文字幕久久| 国产精品福利片免费看| 亚洲av永久中文无码精品综合| ww在线观视频免费观看w| 免费国产不卡午夜福在线| 亚洲日本在线看片| 亚洲成a人无码亚洲成www牛牛| 免费a级毛片高清视频不卡| 亚洲va久久久久| 免费网站看v片在线香蕉| 亚洲av午夜成人片精品网站 | 亚洲国产成人综合精品| 日产乱码一卡二卡三免费| 亚洲最新永久在线观看| 最近2019年免费中文字幕高清| 国产精品亚洲高清一区二区| 久久久免费观成人影院| 亚洲一区二区影院| 91免费精品国自产拍在线不卡| 亚洲精品蜜夜内射| 亚洲av片一区二区三区| 亚洲精品国产suv一区88| 一本久久综合亚洲鲁鲁五月天 | 鲁大师在线影院免费观看| 亚洲AV无码久久久久网站蜜桃| 美女在线视频观看影院免费天天看 | 中文字幕在线观看免费| 日本黄页网站免费| 一级黄色片免费观看| 久久久久久亚洲精品| 久久99久久成人免费播放| 亚洲精品私拍国产福利在线| 最近中文字幕无吗免费高清| h视频在线观看免费| 亚洲精品偷拍无码不卡av| 国产性生交xxxxx免费| 小草在线看片免费人成视久网| 亚洲gv白嫩小受在线观看| 亚洲人成电影网站免费| 国产免费久久精品99久久|