軟件藝術思考者  
          混沌,彷徨,立志,蓄勢...
          公告
          日歷
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          隨筆分類(86)

          隨筆檔案(85)

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

           
          現在后臺分成如下幾個層:
          Domain:提供getter/setter
          Dao:接口,定義了持久化方法,CRUD
          DaoImpl:Dao的實現
          Service:業務邏輯

          但是在實際的過程中發現,service里面有很多涉及到持久化的查詢、更新操作,那么,這些方法是在dao中定義呢?還是在service中定義和實現?
          比如,對于一個 客戶資料UserOrder 實體
          dao中定義了getUserOrderByID() getAllUserOrder() insertUserOrder() updateUserOrder() delUserOrder()五個方法
          現在需要一個 根據地區查詢客戶getUserByArea(),或者 根據產品線和地區查詢客戶 getUserByAreaSrv()
          這樣的方法,定義在service還是dao中?
          第二個問題。service層肯定是面向客戶端調用的,那么dao層對于客戶端是否暴露?
          就是說,service層中是否提供dao中的方法,比如getAllUserOrder() insertUserOrder()這些方法?
          如果不提供,那么客戶端需要知道哪些是dao中提供的,哪些是service提供的
          如果提供這些方法,意味著所有的方法需要在dao中定義,daoimpl中實現,service中包裝,是否太重復和煩瑣?
          1.
          DAO只負責數據庫操作,不涉及任何邏輯,Service就需要業務邏輯了,比如getUserOrder()在DAO,你就查數據庫就行,在service中,你可能需要首先驗證當前用戶是否有這個操作權限,然后調用DAO,最后記錄日志
          2.需要在dao中定義,daoimpl中實現,service中包裝,是否太重復和煩瑣?
          其實這不會發生,因為你認為getUserByAreaSrv()方法肯定一定要完全從數據庫完成,其實不然,其實我可能只從數據庫查詢一個ID集合,然后,在服務層再通過緩存訪問封裝成完整的Model。這些都需要在Service完成(只是一個比喻)。

          預留Service是為防止你的業務系統復雜化之后有一個插腳的地方。

          現在很多系統就沒有這種插腳的地方,在struts的Action中直接調用Hibernate數據庫操作,如那個日本人做的開發框架RoR就是這樣,這些以喪失可維護性做代價的快速開發都是偽框架。

          所以,為你的系統將來留著Service
          3.我認為Dao層還是不要暴露在最外層為妙,即Service以外的層次都無法調用。否則實體化與應用邏輯以及界面之間的耦合度將無法控制,導致產品的生命周期縮短,可擴展性遭到破壞。
          Service層當然也可以有getUserOrderByID() 這樣的操作,但最好通過調用DAO來實現,或者像banq說的以dao-cache的方式來實現,而不是直接去做實體操作。這樣做可能會感掉有些重復繁瑣,但會給產品今后的升級補充帶來好處。可能會多出這30%的代碼量,但帶來的好處是起碼能延長代碼30%的生命。
          Service的方法定義和方法內的參數定義更傾于業務邏輯,而不是存儲方式。而Dao的定義則跟存儲方式直接掛鉤,而不需要過度考慮業務邏輯。所以代碼上的“繁瑣”恰恰代表了邏輯上的“簡單”。
          更重要的是Service是必須的。
          22一般service層是怎么實現的?是不是就是一個擁有很多靜態方法的類,每個靜態方法處理一些業務邏輯,還是有什么其它的方法,望指教
          1我還有疑問,比如CoreFeeService好像是操作CoreFee這個domain bean的,如果我有一段業務邏輯,是調用CoreFeeService改變CoreFee的一些屬性,然后將CoreFee持久化到數據庫,接著可能要調用另一個domain bean的service方法。

          在Struts框架中,這段代碼是寫在Action中,還是別的地方,Action又好像應該只控制轉發,不應該有業務的代碼在里面。但像上面那樣,可能還有事務處理,這時我該怎么做好呢?
          2你描述的這段設計本來就是包含了業務邏輯。當然應該在Service里。service本身包含了粒度不同的操作,粗粒度的操作(方法)里可以包含很多細粒度的操作。這些細粒度的操作可以是private,也可是是public(如果別的action需要它)。
          Action的概念當然跟業務本身是有一定關系的。你可以在action的代碼中表示出一些業務上的邏輯關系,但要節約。能在service中實現的最好在service中。這對程序結構是有好處的。
          你說:“Action又好像應該只控制轉發,不應該有業務的代碼在里面”——這句話體現出你可能已經成為“框架”的“受害者”了。要用“框架”來提煉你的設計,而不要用來約束你的思維。不要指望從“框架”中找到理清軟件開發一切思路的“銀彈”——因為它根本不存在。
          posted on 2006-07-24 16:02 智者無疆 閱讀(1752) 評論(5)  編輯  收藏 所屬分類: software project
          評論:
          • # re: 關于軟件分層的討論  白白 Posted @ 2006-07-24 17:43
            支持支持!!
            http://hi.baidu.com/luzhu33  回復  更多評論   

          • # re: 關于接口  智者無疆 Posted @ 2006-07-25 10:56
            關于接口, 我再來廢話幾句:
            有時候, 一個東西可以“ 是” 幾個東西。不明白這句話嗎? 我就拿我自己來舉個例子吧:
            我“ 是”一個程序員、一個老師、一個作者、一個父親… … 你可以說我“ 實現了老師的接口”,
            學生們會向我詢問關于上課的問題。我還“ 實現了父親的接口”, 但是我的學生可能知道這
            一點, 也可能不知道。如果他們知道這一點, 他們就可以放心的向我詢問關于撫養小孩的問
            題了。
            但是, 盡管我實現了所有這些接口, 我還有一個抽象類— — “ 人”。這個抽象類給我提
            供了所有的默認行為( 比如說我偶爾會走背運)。  回復  更多評論   

          • # re: 關于接口  智者無疆 Posted @ 2006-07-25 10:59
            面向接口編程
            面向接口編程
            在前面的章節中,我們提到一個接口設計的例子。為什么我們提倡接口的設計呢?Martin Fowler在他的分析模式一書中指出,分析問題應該站在概念的層次上,而不是站在實現的層次上。什么叫做概念的層次呢?簡單的說就是分析對象該做什么,而不是分析對象怎么做。前者屬于分析的階段,后者屬于設計甚至是實現的階段。在需求工程中有一種稱為CRC卡片的玩藝兒,是用來分析類的職責和關系的,其實那種方法就是從概念層次上進行面向對象設計。因此,如果要從概念層次上進行分析,這就要求你從領域專家的角度來看待程序是如何表示現實世界中的概念的。下面的這句話有些拗口,從實現的角度上來說,概念層次對應于合同,合同的實現形式包括接口和基類。簡單的說吧,在概念層次上進行分析就是設計出接口(或是基類),而不用關心具體的接口實現(實現推遲到子類再實現)。結合上面的論述,我們也可以這樣推斷,接口應該是要符合現實世界的觀念的。

            在Martin Fowler的另一篇著作中提到了這樣一個例子,非常好的解釋了接口編程的思路:


            interface Person {
            public String name();
            public void name(String newName);
            public Money salary ();
            public void salary (Money newSalary);
            public Money payAmount ();
            public void makeManager ();
            }
            interface Engineer extends Person{
            public void numberOfPatents (int value);
            public int numberOfPatents ();
            }
            interface Salesman extends Person{
            public void numberOfSales (int numberOfSales);
            public int numberOfSales ();
            }
            interface Manager extends Person{
            public void budget (Money value);
            public Money budget ();
            }



            可以看到,為了表示現實世界中人(這里其實指的是員工的概念)、工程師、銷售員、經理的概念,代碼根據人的自然觀點設計了繼承層次結構,并很好的實現了重用。而且,我們可以認定該接口是相對穩定的。我們再來看看實現部分:


            public class PersonImpFlag implements Person, Salesman, Engineer,Manager{
            // Implementing Salesman
            public static Salesman newSalesman (String name){
            PersonImpFlag result;
            result = new PersonImpFlag (name);
            result.makeSalesman();
            return result;
            };
            public void makeSalesman () {
            _jobTitle = 1;
            };
            public boolean isSalesman () {
            return _jobTitle == 1;
            };
            public void numberOfSales (int value){
            requireIsSalesman () ;
            _numberOfSales = value;
            };
            public int numberOfSales () {
            requireIsSalesman ();
            return _numberOfSales;
            };
            private void requireIsSalesman () {
            if (! isSalesman()) throw new PreconditionViolation ("Not a Salesman") ;
            };
            private int _numberOfSales;
            private int _jobTitle;
            }



            這是其中一種被稱為內部標示(Internal Flag)的實現方法。這里我們只是舉出一個例子,實際上我們還有非常多的解決方法,但我們并不關心。因為只要接口足夠穩定,內部實現發生再大的變化都是允許的。如果對實現的方式感興趣,可以參考Matrin Fowler的角色建模的文章或是我在閱讀這篇文章的一篇筆記。

            通過上面的例子,我們可以了解到,接口和實現分離的最大好處就是能夠在客戶端未知的情況下修改實現代碼。這個特性對于分層技術是非常適用的。一種是用在層和層之間的調用。層和層之間是最忌諱耦合度過高或是改變過于頻繁的。設計優秀的接口能夠解決這個問題。另一種是用在那些不穩定的部分上。如果某些需求的變化性很大,那么定義接口也是一種解決之道。舉個不恰當的例子,設計良好的接口就像是我們日常使用的萬用插座一樣,不論插頭如何變化,都可以使用。

            最后強調一點,良好的接口定義一定是來自于需求的,它絕對不是程序員絞盡腦汁想出來的。

              回復  更多評論   

          • # re: 關于接口  智者無疆 Posted @ 2006-07-25 11:09
            到今天,我徹底的明白了為什么有些服務層對象要用接口來聲明了。這是因為當我們在action里面用接口來聲明業務對象以后,不管你以后怎么修改業務對象的實現類都可以,甚至包括更改類名(實現類)都不用修改action里的代碼。  回復  更多評論   

          • # re: 關于軟件分層的討論  王勝利 Posted @ 2006-07-25 17:46
            頂  回復  更多評論   

           
          Copyright © 智者無疆 Powered by: 博客園 模板提供:滬江博客


             觀音菩薩贊

          主站蜘蛛池模板: 德江县| 江达县| 宜章县| 牙克石市| 久治县| 开封市| 手游| 安乡县| 兰州市| 葵青区| 文安县| 峨眉山市| 马公市| 开原市| 抚远县| 万安县| 波密县| 万全县| 蓬莱市| 饶河县| 涡阳县| 正定县| 巨鹿县| 普格县| 济阳县| 呼伦贝尔市| 汝城县| 兴和县| 兴山县| 平乡县| 济宁市| 台安县| 惠来县| 裕民县| 建湖县| 桃江县| 安岳县| 手游| 辛集市| 五峰| 邢台县|