<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 連載:面向對象葵花寶典:思想、技巧與實踐(26) - 類模型三板斧 **類模型設計其實就是程咬金打天下 -- 三板斧 而已 :)** **第一斧(照貓畫虎):領域類映射** 面向對象類設計首先要解決的一個問題是:類從哪里來?? 有的人可能會認為,要發揮想象力、創造力。。。。。等各種“力”——這種方法的主要問題是:我們不是在進行純粹的藝術創造,而是要最終滿足客戶需求,而不能天馬行空。 有的人可能會想到,參考其它的系統吧,把類似系統拿過來改吧改吧 ——這種方法的主要問題是:如果沒有其它類似系統給你參考呢 ? 還有的人干脆就說:拍腦袋吧,憑感覺吧 —— 這種方法的主要問題是:猴子能敲出莎士比亞全集么 ? 看起來以上方法都不太可行,那究竟如何才能從哪里找到我們需要的類呢? 相信絕大部分認真看書的同學都會靈光一閃:領域模型。 我們將上一章中的領域模型圖拿出來,重新再看一下: ![](https://box.kancloud.cn/2016-01-20_569f5cca458ea.jpg) 相信不用我多說,絕大部分同學一眼就能看出:哇塞,這不就是類么? 確實是這樣的,**領域模型中的“領域類”,是設計模型中“軟件類”最好的來源**。通過“領域類”來啟發我們設計最初的“軟件類”,具有如下幾個明顯的**優點**: 1)軟件類來自領域類,領域類來自用例,用例來自客戶,這樣一環扣一環,軟件類的正確性得到了保證,不用擔心拍腦袋帶來的問題; 2)領域類到軟件類的轉換非常簡單,不需要天才的創新,或者豐富的想象力,只要掌握基本的面向對象的知識就能完成,菜鳥也能做設計; 3)不需要參考其它系統,不用擔心沒有參照物時無法設計的問題; 從領域類到軟件類的轉換操作非常簡單,基本上就是一個照貓畫虎的過程。 **【類篩選】** 雖然我們說從領域類到軟件類是一個照貓畫虎的過程,但并不意味著將領域類全盤拷貝過來即可。主要的原因在于“軟件類”是軟件系統內部的一個概念,而領域類是業務領域的概念,并不是每個領域類最終都會體現在軟件系統中。 以POS機的領域類為例,領域類“顧客”不需要轉換為軟件類,因為顧客是POS機業務領域的一個重要參與者,但并不是POS機內部需要實現的一個實體,在POS機業務中,顧客甚至都不是和POS機直接交互的實體,站在POS軟件系統的角度來說,顧客和POS機其實沒有任何關系。 對于屏幕、鍵盤、掃描儀這些輸入輸出設備,一般情況下我們認為它們是POS機系統硬件的一部分,而并不是POS機軟件系統的一部分。但假如POS機有一個需求是既支持圖形界面輸出,又支持字符界面輸出,那么POS的軟件系統就需要處理這種和屏幕相關的需求了,此時屏幕就是POS機軟件系統的一部分了,需要將領域類轉換為軟件類。為了簡單處理,接下來的分析中,輸入輸出設備不做轉換。 經過篩選后,剩下的領域類就需要都轉換為軟件類,具體如下: 收銀員、商品、交易、小票、支付、信用卡、會員卡、現金、購物卡。 **【名稱映射】** 篩選完成后,我們開始講領域類轉換為軟件類,轉換的方法很簡單,首先不管三七二十一,將每個領域類都用一個軟件類與對應,名稱都保持一樣即可。 有的同學可能擔心這樣設計是否會不符合面向對象設計的要求,是否會導致設計質量不高。。。。。。等等,其實這種擔心是多余的,因為我們后續還有很多工作要做,目前做的只是一個開始工作。 **【屬性映射】** 通過名稱映射的方法得到軟件類后,接下來就是要設計類的屬性了。由于領域類中也已經有了屬性,因此我們也只需簡單的照搬過來即可。 **【提煉方法】** 軟件類的屬性設計完成后,接下來就需要設計軟件類的方法了。但這次我們就沒有那么好的運氣了,因為領域類中并沒有方法!因此我們不能通過簡單映射的方法來獲取方法,必須采取其它手段。 和類的設計一樣,類方法的設計同樣不能采取“創造力、參考其它系統、拍腦袋”等方式來完成,為了確保正確性,類的方法設計也同樣應該能夠從已有的模型中推導出來。 由于已經明確領域模型中沒有方法了,因此就不能從領域模型中得到軟件類的方法,剩余只有一個“用例模型”了,因此我們鎖定“用例模型”,看看如何從中找到我們所需要的方法。 其實方法也很簡單,概括一下就是:**找動詞**。 你可能不敢相信自己的眼睛,這么簡單,那幾乎初中生都會做設計啊,找動詞誰不會呢? 然而不管你信不信,這一步確實是這么簡單,當然,如果面向對象設計只是到此為止,那確實初中生也是可以做的,但實際上這只是面向對象類設計的開始步驟而已,后面的工作還多著了,所以完全不用擔心初中生來搶你的飯碗。 我們以POS機為例,來看看如何通過“找動詞”這種技巧來找到軟件類的方法。 如下是POS機的用例,我們將相關動詞都**加粗**顯示: 【用例名稱】 買單 【場景】 Who:顧客、收銀員 Where:商店的收銀臺 When:營業時間 【用例描述】 1.?顧客**攜帶**選擇好的商品到收銀臺; (這一步沒有異常) 2.?收銀員逐一**掃描**商品條形碼,系統根據條形碼**查詢**商品信息; 2.1?掃描儀壞了,必須支持**手工輸入**條形碼; 2.2?商品的條形碼無法掃描,必須支持**手工輸入**條形碼; 2.3?條形碼能夠掃描,但查詢不到信息,需要收銀員和顧客**溝通**,放棄購買此產品 3.?掃描完畢,系統**顯示**商品總額,收銀員**告訴**顧客商品總額; (這一步沒有異常) 4.?顧客將錢**交給**收銀員; 4.1?顧客的錢不夠,顧客和收銀員溝通,**刪除**某商品; 4.2?顧客的錢不夠,顧客和收銀員溝通,**刪除**某類商品中的一個或幾個(例如買了5包煙,去掉兩包) 4.3?顧客覺得某個商品價格太高,要求**刪除**某商品; 4-A:顧客使用信用卡**支付** 4-A.1?信用卡支付流程(請讀者自行思考完善,可以寫在這里,如果太多,也可以另外寫一個子用例) 4-B:顧客使用購物卡**支付** ????????4-B.1?購物卡支付流程 4-C:顧客使用會員卡積分**支付** ????????4-C.1?會員卡積分支付流程 5.?收銀員**清點**錢數,**輸入**收到的款額,系統**給出找零**的數目; (這一步沒有異常) 6.?收銀員將找零的錢還給顧客,并**打印**小票; 7.?買單完成,顧客**攜帶**商品和小票**離開**; 【用例價值】 顧客買完單以后,就可以攜帶商品離開,而超市也將得到收入; 【約束和限制】 1.?POS機必須符合國標XXX; 2.?鍵盤使用中文,因為收銀員都是中國人; 3.?一次買單數額不能超過99999RMB; 4.?POS機要非常穩定,至少一天內不要出現故障; 標識出所有的動詞后,還需要進一步的工作: 【篩選】 并不是所有的動詞都一定是軟件類的方法,我們需要將這些動詞識別出來并排除在后續設計范圍之外。 例如: “顧客攜帶選擇好的商品到收銀臺”:這里的“攜帶”是顧客的一個動作,而顧客并不是我們的軟件類; “收銀員告訴顧客商品總額”:這里的“告訴”確實是收銀員的一個動作,而且“收銀員”確實也是我們的軟件類,但這里也要排除“告訴”,因為“告訴”這個動作和POS系統并沒有關系,只是業務流程中的一個步驟而已。 其它需要排除的動詞還有:“需要收銀員和顧客溝通”、“顧客將錢交給收銀員”、“收銀員清點錢數”、“收銀員將找零的錢還給顧客”、“顧客攜帶商品和小票離開” 【提煉】 篩選完不需要的動詞后,剩下的就是我們需要的動詞了,但此時并不能簡單的將所有動詞拿出來直接扔給某個軟件類就行了,我們還需要進行一些加工。 繼續以POS機為例: “收銀員逐一掃描商品條形碼”:這里的“掃描”看起來是“收銀員”的一個動作,而且“收銀員”確實也是我們的軟件類,但其實深究一下,“掃描”這個動詞并不能分配給“收銀員”這個軟件類,因為真正執行“掃描”功能的是“掃描儀”,收銀員只是拿著掃描儀掃描商品,并不是收銀員自己去讀取商品條形碼;類似的動詞還有“必須支持手工輸入條形碼”,也不能算作“收銀員”的功能。 那我們為什么不排除這兩個動詞呢?秘密就在于我們要從這兩個動詞提煉出軟件類的方法。稍作分析,我們就可以發現,無論是“掃描條形碼”,還是“手工輸入條形碼”,其實最終的目的都是“添加本次交易的商品”,因此我們可以提煉出“增加交易商品”的動詞。 還有一種提煉的方法需要從已有的動詞中推斷出來,例如:“掃描完畢,系統顯示商品總額”,這里只提到了“顯示”這個動詞,但相信大部分人都能一眼看出,“顯示”之前肯定要“計算”,不然顯示出來的值從哪里來呢? 有的朋友可能會疑惑,為什么不在用例的時候就寫清楚呢?例如:掃描完畢,系統計算商品總額,然后系統顯示商品總額。這樣不就一目了然的看出來了么? 理想情況下這種想法當然沒錯,但現實往往沒有那么美好,寫用例的產品人員可能經驗不足,也可能表達能力有限,還有可能比較馬虎,或者遺漏了。。。。。。總之會有很多異常情況,因此設計人員必須具備這樣的推斷和判斷能力。 經過這一步驟后,我們獲得的動詞如下: *?增加商品 *?計算商品總額 *?顯示商品總額 *?刪除商品 *?現金支付 *?信用卡支付 *?購物卡支付 *?會員卡積分支付 *?打印小票 當然,以上列出來的動詞并不是就一定是100%的標準答案,不同的人來進行分析和設計,可能略有不同,但總體應該比較相似,畢竟業務是一樣的,而業務需求就是設計最強的約束。 【分配】 識別出有效的動詞后,最有一步就是分配了,即:將從用例中提煉出來的動詞,分配給已經有了屬性的軟件類。這種分配操作很多時候都是按圖索驥,特別是對于有領域經驗的人來說,基本上憑直覺就能基本分配正確。 當然,如果你的經驗并不是很豐富,那么還是老老實實的一個一個來分析吧。 以POS機為例: * 增加商品:很明顯應該分配給“交易”類 * 計算商品總額:分配給“交易”類 *?顯示商品總額:分配給“交易”類 *?刪除商品:分配給“交易”類 *?現金支付:分配給“現金”類 *?信用卡支付:分配給“信用卡”類 *?購物卡支付:分配給“購物卡”類 *?會員卡積分支付:分配給“會員卡”類 *?打印小票:這個動詞的分配存在一定的靈活性,有的人可能認為應該分配給“交易”類,因為打印小票可以認為是“交易”流程中的一個步驟;有的人可能認為應該分配給“小票”類,因為打印小票可以認為是“小票”類的一個基本功能。其實兩者都有一定道理,如果沒有其它更有力的選擇因素,我建議根據個人經驗選擇一個即可,這里我們選擇分配給“小票”。 分配完成后,我們可以看到“交易”、“小票”、“信用卡”、“購物卡”、“會員卡”、“現金”都已經有方法了。 當然,對于有經驗的人來說,以上步驟完全可以在腦海中就迅速完成了,而并不會這樣一步一步的演示給別人看,所以看起來就像變戲法一樣,不知怎么就設計出來了很多的軟件類。 經過上面的處理步驟后,我們得到如下的類圖: ![](https://box.kancloud.cn/2016-01-20_569f5cca68a19.jpg) 與領域模型相比,部分領域類被剔除了,留下來的領域類映射成軟件類后,又增加了方法。雖然還不完善,但軟件類的是越來越有型,越來越清晰了。 **第二斧(精雕細琢):應用設計原則和設計模式** 完成了從領域類到軟件類的映射后,類出來了,屬性也出來了,方法也有了,看起來設計已經大功告成了。 事實上也確實有很多人基本上做到這一步就開始動手編碼了,而且經過一番拼搏,最后發布的系統也能用。 但相信很多人都會有這個疑問:這樣做就夠了么,這樣設計是否是好的設計呢? 要回答這個問題,我們首先要明確:什么叫做“好”的設計呢?? 到目前為止,我們已經有了一個類的設計模型,而且如果按照這個模型去實現的話,最終應該也是能夠滿足用戶的需求,畢竟我們這個類模型是按照“需求模型 -> 領域模型 -> 類模型”這樣一路推導過來的,不會出現大的偏差。 那么,滿足了用戶需求的設計就是好的設計么? 相信有經驗的朋友都會知道答案:“滿足用戶需求”只是設計的一個最基本要求,而不是一個“好設計”的評判標準。 既然如此,那么到底什么才是好的設計呢,是否有明確的標準來進行評價呢? 幸運的是,面向對象領域經過幾十年的發展,確實已經發展出了很多成熟的指導思想和方法,用于評價和指導如何才能做好面向對象的設計。其中最具代表性的就是**“設計原則”和“設計模式”**。 **【設計原則】** 當我們談到面向對象領域的設計原則的時候,我們其實都是在談論羅伯特.C.馬丁(Robert C. Martin ,又叫Bob大叔)的SOLID原則。 這也難怪,Bod大叔實在是太牛了,面向對象領域的設計原則幾乎被他全部包攬了,加上他在他的暢銷書《敏捷軟件開發:原則、模式與實踐》中詳細的將這些原則集中一 一闡述,面向對象領域設計原則的權威非他莫屬。毫不夸張的說,Bob大叔的威名和在面向對象領域中的地位,和設計模式的“四人幫”是不相上下的。 雖然很多資料都將SOLID原則和敏捷開發、測試驅動開發等方法綁定在一起,但我覺得只要是面向對象設計,不管是瀑布流程、、CMM流程、RUP流程、還是敏捷開發流程,都應該應用設計原則以提高設計質量。 參考wiki百科,SOLID設計原則簡單介紹如下: SOLID實際上是取5個設計原則的首字母拼起來的一個助記單詞。具體的設計原則如下(詳細的設計原則,我們會在后面詳細闡述,這里不再詳細展開): | 首字母| 英文簡寫| 英文名稱| 中文名稱| 說明| |--|--|--|--|--| | S| SRP| Single?Responsibility?Principle| 單一職責原則|對象應該只具備單一職責| | O| OCP| Open/Close?Principle| 開放/封閉原則|認為“軟件體應該是對于擴展開放的,但是對于修改封閉的”的概念。| | L| LSP| Liskov?Substitution?Principle| Liskov替換原則|認為“程序中的對象應該是可以在不改變程序正確性的前提下被它的子類所替換的”的概念| | I| ISP| Interface?Segregation?Principle|[接口隔離原則](http://zh.wikipedia.org/w/index.php?title=%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E5%8E%9F%E5%88%99&action=edit&redlink=1)|多個特定客戶端接口要好于一個寬泛用途的接口| | D| DIP| Dependency?Inversion?Principle|[依賴反轉原則](http://zh.wikipedia.org/wiki/%E4%BE%9D%E8%B5%96%E5%8F%8D%E8%BD%AC%E5%8E%9F%E5%88%99)| 依賴于抽象而不是一個實例| (wiki百科鏈接如下: http://zh.wikipedia.org/wiki/SOLID_(%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1)) 前面我們簡單的八卦了一下,現在回歸正題:設計原則有什么用? 其實和所有的原則一樣,設計原則也是一個判斷標準,說通俗點,設計原則就像是木匠手中的尺子,尺子是用來衡量木材的長短的,而設計原則就是衡量類設計的“尺子”:量一量,看長了還是短了,還是正好,長了就裁短一些,短了就加長一些。經過如此衡量并調整,最終就能夠得到我們希望的設計作品。 當然,和木匠的尺子稍有不同,木匠不用尺子就做不出能用的家具,但我們不用設計原則的話,其實還是能夠做出滿足需求的系統的。 既然這樣,我們為什么一定要用設計原則呢?ARTHUR J.RIEL在《OOD啟思錄》一書中針對這個問題給出了非常形象的解釋: 你不必嚴格遵守這些原則,違背它也不會被處以宗教刑罰。但你應當把這些原則看做警鈴,若違背了其中的一條,那么警鈴就會響起。”-------ARTHUR J.RIEL,《OOD啟思錄》 也就是說,如果違背了這些設計原則,就可能有危險,但究竟是什么危險呢,警鈴要警告我們什么呢,是火災、水災、地震、陷阱、還是有獅子、老虎。。。。。? 要回答這個問題,還需要回到面向對象的本源:我們在第一章解釋為什么要面向對象的時候提到了面向對象的核心思想是“可擴展性”,這其實就是我們應用設計原則的根本目的:保證可擴展性。如果我們不遵守這些設計原則,警鈴就會響起,提醒我們:你的設計可擴展性會有問題! 除了設計原則外,后面要講到的設計模式,其本質也是為了提高可擴展性。這也是為什么我們通過領域類映射得到了很多軟件類之后,還需要不辭辛勞的繼續應用設計原則和設計模式的主要原因,本質上都是為了提高設計的可擴展性。 SOLID設計原則的各個子原則詳細介紹會在后面詳細介紹,這里我們簡單的以POS機為例,看看如何應用設計原則。 仔細觀察我們通過領域類映射得到的軟件類,可以發現一個很明顯不符合SOLID原則中的DIP原則的地方,即:“交易類”直接依賴“會員卡”、“購物卡”、“信用卡”、“現金”4個子類,這樣的實現不符合DIP原則,當需要增加新的支付方式時,“交易類”也需要跟著修改。 既然不滿足DIP設計原則,那么我們就按照DIP原則的要求,提取出一個支付的父類來,即:“交易類”依賴“支付類”,“會員卡”、“購物卡”、“信用卡”、“現金”都繼承“支付”類。具體實現如下: ![](https://box.kancloud.cn/2016-01-20_569f5cca808d6.jpg) 可以看到,應用DIP設計原則之后,我們又多出了一個“支付”的類,這個類原來在領域模型中是沒有的,而是我們在設計階段“創造”出來的。 對于其它各個類,我們都可以依次使用設計原則進行判斷,當發現不符合設計原則的設計時,就采取增加、刪除、合并、拆分等手段,使我們的設計逐步改進,最終達到符合設計原則的目的。 **【設計模式】** 相比設計原則來說,設計模式更加普及和流行,當我們談到設計方法的時候,大部分人肯定都會想到設計模式,設計模式如此深入人心,幾乎到了言必談設計模式的地步。 和設計原則類似,當我們談論設計模式的時候,我們其實都是在談論GOF(Gang of Four,中文翻譯為“四人幫”)在經典名作《設計模式 ?--可復用面向對象軟件的基礎》一書中提到的設計模式。 通俗的講,設計模式是用于指導我們如何做出更好的設計方案,而前面提到的設計原則,其作用也是這樣的。那么,設計原則和設計模式,我們該如何選擇? 有的朋友可能會以為這兩個是二選一的關系,要么用設計原則,要么用設計模式。這種理解是錯誤的,設計原則和設計模式并不是競爭關系,正好相反,它們是互補的關系。 設計原則和設計模式互補體現在:**設計原則主要用于指導“類的定義”的設計,而設計模式主要用于指導“類的行為”的設計**,更通俗一點的講:設計原則是類的靜態設計原則,設計模式是類的動態設計原則。 一般情況下,我們是采用“先設計原則,后設計模式”的方法來操作的。 設計模式的相關內容會在后文詳細介紹,這里我們以POS機為例,看看如何應用設計模式來優化我們的設計。 通過分析應用設計原則優化后的類,我們發現“信用卡”這個類存在優化的空間,因為國際上存在不同的信用卡,最常見的有中國銀聯(UnionPay)、Visa、MasterCard這幾種,每種信用卡在支付的時候需要接入不同的機構,其接入方式和協議肯定都是有一定差異的。為了封裝這種差異以支持后續更好的擴展,我們應用設計模式的Bridge模式,提取出“信用卡處理”這個類,這個類的主要處理“連接、認證、扣款”這樣的職責。UnionPay、Visa、MasterCard都繼承“信用卡處理”這個類。具體如下: ![](https://box.kancloud.cn/2016-01-20_569f5cca977e0.jpg) **第三斧(照本宣科):拆分輔助類** 經過前面的設計步驟之后,面向對象類的設計工作已經完成,我們輸出了完整的類模型,看起來已經可以開始動手編碼了,你是否舒了一口氣,看著自己的設計作品,不由得產生了一種自豪感呢? 確實值得自豪,畢竟我們一步一個腳印,從最初僅僅存在于客戶腦袋中的需求,逐步的推導、演變、設計出了能夠付諸實施的類模型了。但在最終實施之前,還有一點小小的動作要完成,這就是我們的拆分輔助類操作。 拆分輔助類的主要目的是為了使我們的類在編碼的時候能夠滿足一些框架或者規范的要求。比如說常見的MVC模式,將一個業務拆分成Control、Model、View三個元素;J2EE模式中,將對象分為PO、BO、VO、DTO等眾多對象。 之所以說這是一點小小的動作,是因為這個動作確實很簡單,只要將我們設計出來的類,按照規范要求,一 一對應分拆即可。 以POS機為例,假如我們的框架要求提供DAO對象,負責數據庫的相關操作,則“購物卡”類就應該拆分為兩個:“購物卡”、“購物卡DAO”,其中“購物卡”用于負責提供“支付”功能給“交易”類調用,“購物卡DAO”用于負責從數據庫讀取購物卡信息,修改數據庫中購物卡余額等操作。 ![](https://box.kancloud.cn/2016-01-20_569f5ccab4b18.jpg) 需要注意的是,拆分設計輔助類僅僅是為了滿足框架或者規范的要求,**本身并不是一個設計的步驟,而是實施的一個步驟**,所以我們一般都不需要將拆分的輔助類體現在類模型中,僅僅在編碼的時候拆分即可。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看