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

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

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

    我愛oo,我愛java

    交流blog QQ:421057986 oofrank@donews

    2006年1月20日 #

    DAO-持久層-領域對象-貧血模型

    原文


    關于"貧血模型"的討論幾乎沒有停止過,在openfans.org的開發過程中,我們也討論了很久,我覺的有很多東西應該記下來:
    明確一下意思先:
    DAO:數據操作對象,會操作數據庫
    持久層:能提供對象持久化服務的一系列組件或服務
    領域對象:描述領域模型的對象,是通過業務分析進行系統建模的產物
    貧 血模型:就是domain object只有屬性的getter/setter方法的純數據類,所有的業務邏輯完全由一個所謂的Manager來完成(又稱 TransactionScript),這種模型下的domain object被Martin Fowler稱之為“貧血的domain object”
    常見的類基本結構如下:
    一個業務數據類叫做Item,
    一個DAO接口類叫做ItemDao
    一個DAO接口實現類叫做ItemDaoHibernateImpl
    一個業務邏輯類叫做ItemManager(或者叫做ItemService).

    觀察上面的幾個類很容易發現問題:
    1:Item和ItemManager實際是操作與數據的關系,實際完成的就是經典OO中的一個對象的能力;
    2:當有許多Item時 類組變得很龐大,產生很多 xxxDao xxxImpl xxxManager 其中包含大量重復代碼;
    按<<重構>>的觀點,上述代碼存在以下臭味:
    1:重復的代碼?? xxxDao xxxImpl xxxManager(通常)
    2:霰彈式修改,一個變化影響多個類,類之間不夠高內聚 item變化-->Dao,Impl,Manager均要變動
    3:依戀情結,兩個類之間互相作用過多 item<->Manager
    4:平行繼承體系,當增加一個新類時總是要增加另一個類
    5:夸夸其談未來性,在沒有任何暗示的情況下考慮擴展? Dao,實際HibernateImpl可能n年內是唯一的Dao實現
    6:純稚的數據類,只有數據的類? item

    我覺的 貧血模型 是系統分析設計方向性錯誤的產物:
    1:沒有進行領域建模---以數據表結構為中心,而不是業務模型為中心的思考方式,使設計人員選擇Item為考慮問題的出發點
    2:將DAO與持久層混淆---我們需要的一種持久化服務,DAO緊緊是提供數據操作能力而已,Hibernate是一種高級的服務(他已經包含了DAO,而不是相反),已經完成了所有的持久層服務.
    3:過于強調低偶合---將一些本來一些提供單一職責的內容分散在多個單元中使 客戶端 依賴更多的接口,而忘記了高內聚原則.
    4:Spring的能力限制---由于Spring現階段不支持對于領域模型的服務注入,使設計人員將操作和數據分開,并將領域變為DataOnly的.
    ? (Spring2.0將在很大程度上解決這個問題)
    ?
    我認為良好的解決方案:
    ? 首先領域建模,建立領域模型-->合并前面所說的Item和ItemManager成為 domainItem;對于數據庫服務,
    ? 1:如果考慮領域層包含數據操作能力,則建立DAO并選擇其它好的DAO方案比如IBATIS或Hibernate之類的組件;
    ? 2:如果考慮將數據庫(或其他存儲界質)存儲考慮在領域之外成為持久層,
    ? ??? a:則或者對持久層框架同時建模,同時選擇合適的組件為持久層服務提供存儲服務(包括DAO--亦可選擇IBATIS/Hibernate組件),
    ? ??? b:或者直接使用Hibernate/JDO等框架實現持久化服務,領域層直接使用持久層服務,對領域對象進行持久化和反持久化(從持久層獲取以持久化的對象).
    ?
    其他:
    ? 實際上,作為一種解決方案,所謂"貧血模型"的具體使用,并不會有太大的問題,尤其是使用一些代碼生成工具或已經做好相應的基本框架時,很多軟件的核心價 值都在于對客戶提供的服務,而其內部則成為黑盒,我們只要合理的解決業務問題,就是"王道"了,對于代碼的臭味,可以慢慢重構--這也需要成本呀.?
    ?
    再其他:
    有人說,我們的業務就是CRUD,領域模型只有數據類就足夠了.我覺的這是搞錯了方向------只有CRUD時,只有處理CRUD的那些類才有必要進行建模(他們才是領域模型),而所謂的User\Item等數據類則完全沒有必要進行建模,更不要談領域了.

    貧血之外:
    實際上,軟件\OO方法的外延大的很,更多問題與數據庫存儲無關(但也有貧血問題),所以建模才是根本,OO方法的原則才是我們必須掌握的.

    posted @ 2006-04-10 22:21 兼聽則明 閱讀(6548) | 評論 (4)編輯 收藏

    SQLServer的一個bug

    SQLServer一個bug終于被我碰上了

    我有一個表使用字符類型存儲數字值,想進行匯總計算:

    sum(case when isnumeric(FieldName)=0 then 0 else cast  (FieldName as numeric) end)
    簡單試了一下沒有問題,可是今天數據中有一個 ’2.1234567E7‘  isnumeric返回1 cast 返回錯誤

    嗚嗚。。。。
    怎么辦......

    posted @ 2006-02-05 22:37 兼聽則明 閱讀(346) | 評論 (0)編輯 收藏

    使用Quartz要注意的一個問題


    當設置一個Schedule的startDate早于 new Date(),并且調度周期又觸發于startDate和new Date()之間時,就會立即觸發當前job。簡單的解決方式是將startDate設為new Date().

    posted @ 2006-01-23 00:52 兼聽則明 閱讀(429) | 評論 (0)編輯 收藏

    使用abator自動生成ibatis代碼的經驗 及碰到的問題的解決方案


    1:abator下載:http://ibatis.apache.org/abator.html
    2:將abator安裝到eclipse中
    3:此時可以新建一種文件類型:Abator for iBATIS Configuration File,建立一個
    4:在 jdbcConnection 中設置要mapping的數據庫的jdbc連接
      classPathEntry 是你的jdbc driver類路徑
    5:javaModelGenerator,sqlMapGenerator,daoGenerator 分別設置 java dataObject、sql mapping文件和 DAO 接口、實現類的生成位置:targetPackage 目標包,targetProject:eclipse項目
    6:daoGenerator 中可以設置屬性  type: ibatis 或 spring 指定生成的dao實現類是使用com.ibatis.dao.client.template.SqlMapDaoTemplate
    還是
    org.springframework.orm.ibatis.support.SqlMapClientDaoSupport
    7: table 中 tableName 指定要處理的表名
      可以有多個table
    8:table中可以包含子元素 generatedKey: 使Insert方法可以返回值--由指定的column mapping
    9:generatedKey中的sqlStatement屬性可以是獲取sequence的SQL,也可以是獲取自增值的SQL
      比如:Oracle的 select theSequence.nextVal from dual
           SQLServer的 SELECT @@IDENTITY as  column_name
    10:保存文件,選中文件,右鍵菜單選擇Generate iBATIS Artifacts! ok...



    使用abtor生成的iBatis代碼出現xml解析錯誤的解決方案
    如果按上述方式生成的代碼有xml解析錯誤:  請下載這個

    注意,該文件名為Abator.rar.txt實際是一個rar文件,只是上傳服務器有文件類型限制 所以只好加了擴展名txt。
    請去掉.txt后解壓。

    使用
    org.apache.ibatis.abator.core_0.5.1.jar
    替換調你的 eclipse\plugins 的同名文件 即可。

    然后重新生成代碼。 OK 應該可以咯....

    我改了一點代碼,需要可以留言。

    posted @ 2006-01-21 13:51 兼聽則明 閱讀(9078) | 評論 (12)編輯 收藏

    在eclipse-plugin開發中碰到的怪問題:(eclipse 3.1.1 + wtp1.0)

    一個popupMenus Extensions,
    objectContribution:objectClass*: org.eclipse.core.resources.IFile

    在action的Class代碼中:
    public void selectionChanged(IAction action, ISelection selection) {
        StructuredSelection ss = (StructuredSelection) selection;
            this.selectedFile==(IFile)ss.getFirstElement(); //此處拋出異常
    }

    上述代碼的異常非常奇怪:
    根據的的跟蹤,ss.getFirstElement()返回值是File,該類實現了IFile接口,
    而且我用 ss.getFirstElement().getClass().isAssignableFrom(IFile.class)返回是false;
    真是奇怪!---有人知道為什么嗎?

    另外在實踐eclipse plugin開發過程中也有幾個心得:(肯定能用,但未必最佳)

    1、如果開發plugin,所有的依賴庫都要包含到 Plug-in Dependencies 中;而不能只是引入到工程中。
    2、如何輸出到console:
    MessageConsole mc=new MessageConsole("****",null);
    IConsole[] cs=new IConsole[1];
    cs[0]=mc;
    ConsolePlugin.getDefault().getConsoleManager().addConsoles(cs);
    mc.activate();
    PrintStream out=new PrintStream( mc.newOutputStream());
    out.println("*******.");
    3、如何獲取依賴工程的輸出路徑:
    selectedProject:當前工程---由用戶選擇
    String[] ps= selectedProject.getRequiredProjectNames();                
    IWorkspace w= selectedProject.getProject().getWorkspace();
    for(int i=0;i<ps.length;i++){
    IResource r=w.getRoot().findMember(ps[i]);
    try{
        IJavaProject jp=new JavaProject((IProject)r,null);                
        File source=new File(jp.getProject().getLocation().append(jp.getOutputLocation().removeFirstSegments(1)).toOSString());
            //作你的事情.....
    }catch(Exception e){
          //不是javaProject                                
        e.printStackTrace();                            
    }                
    4、如何使用進度Dialog:
    Shell shell = new Shell();
    ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);        
    IRunnableWithProgress thread = new SomeRunner(shell);            
    dialog.run(true, false, thread);
    //=============================
    private class SomeRunner implements IRunnableWithProgress {
        public void run(IProgressMonitor monitor)throws InvocationTargetException, InterruptedException {
        monitor.beginTask("一些信息", 數值-總工作量);
            for(;;){
            // 一些工作
            monitor.worked(數值-已完成工作量); //實際中,我得情況不太相符,不明白,但差不多 :(
            monitor.setTaskName("一些信息");
         // 一些工作    
           }
            monitor.done();
        }
    }


    posted @ 2006-01-20 18:45 兼聽則明 閱讀(596) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲色精品三区二区一区| 永久免费av无码网站大全| 在线看亚洲十八禁网站| 亚洲明星合成图综合区在线| 亚洲人成色7777在线观看| 免费看国产曰批40分钟| 青青久在线视频免费观看| 亚欧免费视频一区二区三区| 最好免费观看高清在线| 一区二区免费电影| 黄网站在线播放视频免费观看| 亚洲精品无码永久在线观看男男 | 亚洲AV日韩综合一区尤物| 亚洲国产高清在线| 精品亚洲永久免费精品| 亚洲人成网站色在线入口| 免费午夜爽爽爽WWW视频十八禁| 久久久久久久久免费看无码| 最近在线2018视频免费观看| 成人无码WWW免费视频| 成人A毛片免费观看网站| 五月天婷婷免费视频| 黄页网址在线免费观看| AV激情亚洲男人的天堂国语| 亚洲国产一区二区三区在线观看 | AV无码免费永久在线观看| 永久免费在线观看视频| 99久热只有精品视频免费看 | 亚洲AV无码精品色午夜果冻不卡| 亚洲日韩在线观看| 在线亚洲精品自拍| 亚洲一区二区三区无码中文字幕| 亚洲日产无码中文字幕| 亚洲热线99精品视频| 亚洲爆乳精品无码一区二区三区 | 99ee6热久久免费精品6| 一级毛片在线免费看| 国产成人yy免费视频| 91嫩草国产在线观看免费| 成年轻人网站色免费看| 日韩中文无码有码免费视频|