<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7430228878465597108</id><updated>2012-02-02T19:57:52.795-08:00</updated><category term='工具'/><category term='開發流程'/><category term='架構'/><category term='系統分析'/><title type='text'>火星紀事</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>38</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-7913853374308874289</id><published>2011-05-31T18:01:00.000-07:00</published><updated>2011-05-31T19:37:42.098-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>UseCase到領域建模</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言&lt;/span&gt;&lt;br /&gt;最近拜讀邱郁惠老師的大作「學會UML/OOAD，這樣開始就對了」，不禁想起從UseCase到領域模型曾是我的一大瓶頸。也許會有人覺得奇怪，這中間不就是名詞轉化為類別，動詞轉化為函式…。我只能說絕不僅是如此，這裏就借用邱老師書上第一個使用者案例，概說一下我的想法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;使用者案例&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;用例名稱：會員登入&lt;br /&gt;啟動者：會員&lt;br /&gt;支援者：&lt;br /&gt;&lt;br /&gt;主要流程：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;會員輸入電郵與密碼 &lt;/li&gt;&lt;li&gt;系統確認會員身分之後，出現歡迎訊息&lt;/li&gt;&lt;/ol&gt;替代流程：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;資料不完整：客戶端提醒會員填入資料，直到資料完整才傳送到伺服端 &lt;/li&gt;&lt;li&gt;驗證失敗：累積5次登入失敗，即鎖定，並出現請會員主動聯絡系統管理員的訊息 &lt;/li&gt;&lt;/ol&gt;企業規則：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;BR1：以會員電郵做為會員代號 &lt;/li&gt;&lt;li&gt;BR2：密碼採用MD5儲存 &lt;/li&gt;&lt;li&gt;BR3：會員累積5次登入失敗，即鎖定該會員帳號。只要登入成功，即失敗次數歸零 &lt;/li&gt;&lt;li&gt;BR4：一個人只能申請一個會員身分 &lt;/li&gt;&lt;/ol&gt;議題與其他：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;帳號密碼變更是否為一使用者案例 &lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;領域模型&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;取自四色原型的觀念，模型必須區分靜態與動態。像PPT這種靜態的物件其屬性應該很少需要修改，所以登入的資訊不適合與會員放於一塊，所以拉出一個較為動態的物件MemberLogin，較為適當。&lt;br /&gt;取自DDD的觀念，規則最好可以獨立成Spec物件，這樣設計時自然會變成可動態抽換，而且說不定日後鎖定的規則不是5次，或再加上間隔時間的限制也說不定。&lt;br /&gt;MemberLoginStatus，也許最後設計時只是個字串、長整數、enum之類，但為了分析上的清晰，我還是傾向將它獨立成類別。&lt;br /&gt;最後的模型圖如下：&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-RX-ByC1PrcU/TeWjyrtG29I/AAAAAAAAARk/49t3nbed3ac/s1600/Model.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 348px;" src="http://4.bp.blogspot.com/-RX-ByC1PrcU/TeWjyrtG29I/AAAAAAAAARk/49t3nbed3ac/s400/Model.png" alt="" id="BLOGGER_PHOTO_ID_5613072601707895762" border="0" /&gt;&lt;/a&gt;&lt;a class="missing wiki"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-7913853374308874289?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/7913853374308874289/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=7913853374308874289' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/7913853374308874289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/7913853374308874289'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2011/05/usecase.html' title='UseCase到領域建模'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-RX-ByC1PrcU/TeWjyrtG29I/AAAAAAAAARk/49t3nbed3ac/s72-c/Model.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3984639506722018605</id><published>2011-05-17T03:02:00.000-07:00</published><updated>2011-05-17T03:09:26.226-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>權限模型思考之二</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;在理解Rhino.Security的設計理念後，我希望為寫找更多的理論基礎，好讓我不要重複的思考這個問題。所以又找到了Enterprise Patterns And MDA這本書中，關於PartRelationShip的描述。以證明照著這麼設計準沒錯。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;PartyRelationShip Archtype&lt;/span&gt;&lt;br /&gt;PartRelationShip這種Archtype這麼定義的，所以有人員或組織(Party)，都必須建立角色 (PartyRole)，PartyRoleType，就是所謂的角色檔。透過角立建立起彼此的關係 (PartyRelationShip)，PartRelationShipType就恕我想像力貧乏，不能想出適合的需求。&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-O14IbpQoCQ8/TdJIPourCHI/AAAAAAAAAQs/F4mqtvI7VI4/s1600/PartyRelation1.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 285px; height: 376px;" src="http://2.bp.blogspot.com/-O14IbpQoCQ8/TdJIPourCHI/AAAAAAAAAQs/F4mqtvI7VI4/s400/PartyRelation1.png" alt="" id="BLOGGER_PHOTO_ID_5607623919498102898" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;整合&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;將兩者整合會推出一個較大的模型，足以代表主流的權限系統觀念&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-s8ue3VxzBWw/TdJIib_GBBI/AAAAAAAAAQ0/qWQLbw_Ty08/s1600/PartyRelation2.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 359px;" src="http://4.bp.blogspot.com/-s8ue3VxzBWw/TdJIib_GBBI/AAAAAAAAAQ0/qWQLbw_Ty08/s400/PartyRelation2.png" alt="" id="BLOGGER_PHOTO_ID_5607624242494833682" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;想像案例&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;某間超市的管理系統。計有經理、店員、會計三種職位，以及5位職員。而經理可以做店員、會計的工作。&lt;br /&gt;首先因為不是什麼複雜的系統，所以沒有Party，只有Employees。而Duties就是系統的角色檔。&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-Ie1lG22OYJE/TdJI3oJdPQI/AAAAAAAAAQ8/0fcJIeBSu_M/s1600/PartyRelation3.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 349px; height: 376px;" src="http://4.bp.blogspot.com/-Ie1lG22OYJE/TdJI3oJdPQI/AAAAAAAAAQ8/0fcJIeBSu_M/s400/PartyRelation3.png" alt="" id="BLOGGER_PHOTO_ID_5607624606536776962" border="0" /&gt;&lt;/a&gt;Duries有階層概念，所以自關聯。這裏要注意的是，一般權限設定是下層的群組可以繼承上層的權限，但這裏反倒是上層的Duty權限愈大。&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-WplaJk_f7R4/TdJJEZm_8LI/AAAAAAAAARE/yUF9GhN2L-c/s1600/PartyRelation4.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 338px;" src="http://1.bp.blogspot.com/-WplaJk_f7R4/TdJJEZm_8LI/AAAAAAAAARE/yUF9GhN2L-c/s400/PartyRelation4.png" alt="" id="BLOGGER_PHOTO_ID_5607624825972453554" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3984639506722018605?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3984639506722018605/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3984639506722018605' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3984639506722018605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3984639506722018605'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2011/05/blog-post_17.html' title='權限模型思考之二'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-O14IbpQoCQ8/TdJIPourCHI/AAAAAAAAAQs/F4mqtvI7VI4/s72-c/PartyRelation1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-1264336024019052902</id><published>2011-05-15T05:23:00.000-07:00</published><updated>2011-05-31T20:43:32.149-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>權限模型思考之一</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;前言&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;權限系統可以說是各系統最基本的部分，在領域知識裏也最容易讓人理解，所以在研究模型時，就從這裏開始。我先從達人Ayende那下載了 Rhino.Security來研究，在搞清楚來龍去脈後，再配合RBAC模型，甚至是MDA中的PartyRelationship也就比較清楚。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;RBAC&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;先讓我們搞清楚什麼是RBAC，基本的概念圖如下。意思是不論是Subject(個人)或Orgaization(組織)，都必須透過Role去取得 Permission所定義的Operation。Session還不明瞭其用意。整個圖的最複雜的，就是Role  Hierarchy。子代角色可以繼承父代的權限，然後一人可以多種角色。&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-dScmP7MwIlY/Tc_Iec-1ulI/AAAAAAAAAQU/TacBLSNaV9M/s1600/RBAC.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 162px;" src="http://4.bp.blogspot.com/-dScmP7MwIlY/Tc_Iec-1ulI/AAAAAAAAAQU/TacBLSNaV9M/s400/RBAC.jpg" alt="" id="BLOGGER_PHOTO_ID_5606920486600948306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Rhino.Security&lt;/span&gt;&lt;br /&gt;先來看一半的ER Model。UsersGroups就是Role，伴隨著自身關聯構成Role  Hierarchy。UsersGroupsHierarchy則是設計考量，畢竟從單一Table取出整顆Tree的所有結點是很不好做。Users透 過UsersToUsersGroups找到扮演的角色，從而知道關聯的權限與操作。應該是基於實際應用的考量，因為Ayende允許User也可以沒有 角色就有權限。至於Allow是指是否可以操作，Level是指兩種以上的角色對某一權限的操作衝突時，何為優先。&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-FziThe4Cr8U/TeW0jeENGHI/AAAAAAAAARs/oPKt7wfCnGw/s1600/Model.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 250px;" src="http://2.bp.blogspot.com/-FziThe4Cr8U/TeW0jeENGHI/AAAAAAAAARs/oPKt7wfCnGw/s400/Model.png" alt="" id="BLOGGER_PHOTO_ID_5613091032046311538" border="0" /&gt;&lt;/a&gt;&lt;a href="http://3.bp.blogspot.com/-qb_LnlxcOn0/Tc_I27g608I/AAAAAAAAAQc/Kdi4DdZwEMU/s1600/uml1.png"&gt;&lt;br /&gt;&lt;/a&gt;再來看另一半的ERModel，這裏是在定義可以操作的物件群組。例如Opereation定義/Employee/Edit這種操作，但它是作用在 Employee這種EntityTypes之上。更進一步，可以分類EntityTypes成EntitiesGroups。 EntitiesGroups還可以有Hierarchy的觀念，例如Employee與它的屬性。&lt;br /&gt;EntityReference與EntityTypes之間，需要一個EntitySecurityKey區隔開，原因我還不太明瞭。 EntityReferencesToEntitiesGroups則是建立物件的群組關係。然後與之前相同 的，EntityGroupsHierarchy是協助產生EntitiesGroups的樹狀結構。Permission不僅能設定 EntitiesGroups，也能單對EntityReference。&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-LqNrqdrAMTA/TeW1P8zj0xI/AAAAAAAAAR8/EZ8CrE6AY-Q/s1600/Model1.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 187px;" src="http://2.bp.blogspot.com/-LqNrqdrAMTA/TeW1P8zj0xI/AAAAAAAAAR8/EZ8CrE6AY-Q/s400/Model1.png" alt="" id="BLOGGER_PHOTO_ID_5613091796212241170" border="0" /&gt;&lt;/a&gt;&lt;a href="http://4.bp.blogspot.com/-hVXxTc33xU4/Tc_JEK-WBVI/AAAAAAAAAQk/ynSr1mq2h1M/s1600/uml2.png"&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;API&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Rhino Security做了個有趣的API讓我們使用，以一種近乎人類語言的方式封裝了權限的操作&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;permissionsBuilderService&lt;br /&gt;&lt;/code&gt;&lt;pre class="wiki"&gt;   .Allow("/Employee/Edit")  //允許什麼樣的操作&lt;br /&gt;.For("Secretary")         //什麼角色，經理&lt;br /&gt;.On("Employee")           //作用在什麼物件群組&lt;br /&gt;.DefaultLevel()           //優先級最低&lt;br /&gt;.Save();&lt;br /&gt;&lt;br /&gt;authorizationService.IsAllowed(secretary_A,employee_A,"/Employee/Edit"); //true&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-1264336024019052902?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/1264336024019052902/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=1264336024019052902' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/1264336024019052902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/1264336024019052902'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2011/05/blog-post.html' title='權限模型思考之一'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-dScmP7MwIlY/Tc_Iec-1ulI/AAAAAAAAAQU/TacBLSNaV9M/s72-c/RBAC.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3017766179934636845</id><published>2010-05-24T08:04:00.000-07:00</published><updated>2010-05-24T08:56:55.060-07:00</updated><title type='text'>Entity 與 Value Object的一點思考</title><content type='html'>&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;前言：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;   　　Entity與Value Object是DDD的重點觀念之一。最基本的定義，Entity帶有Identity，Value Object沒有。一個Value Object與另一個Value Object之所以相同，完全是憑它們的屬性。換言之，如果Value Object換了屬性值，兩個VO之間也就不同了。這跟Entity無論怎麼換，只要ID不動，就是同一個物件是不一樣的。&lt;br /&gt;　　Value Object的另一個特性就是它是immutable的，亦即屬性不可異動，這倒跟Entity的ID是immutable是同涵意的。如果破壞了immutable，物件就不再是之前的那個物件。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Enterprise Pattern：&lt;/span&gt;&lt;br /&gt;　然後我又看了一下POEAA內，對Value Object的定義。沒有ID的小物件，憑屬性辨識，例如Money，DateTime，最合乎的資料庫設計是Embedded Value或Serialized LOB，換句話說就是將VO的屬性內嵌到Table的欄位中。所以Value Object只是Entity的一個Column值，而不是一個外鍵參考是沒錯了。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Address：&lt;/span&gt;　&lt;br /&gt;　為什麼沒事提這個東西，因為DDD說Address是一個VO。因為如果有一群人同住在一個地址，當其中一人要搬出去了，他不能改它的住址，因為只要換了，就會變成大家都換住址了。我如果用上述的觀點來看，住址如果是VO，那應該是每個人都有一個地址VO，換換Column的值怎麼會影響到其他的物件。&lt;br /&gt;　那如果是大家共用一個住址，那又是什麼，不就是Entity嗎？每個人用一個外鍵關連到住址。這讓我腦子登時混亂起來，這是一個immutable的Entity嗎?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;結論：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;　最後我還是接受POEAA的觀念，只有一些小物件適合當VO。最好不要浪費時間分析是否是個Value Object，為DDD而DDD是沒必要的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3017766179934636845?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3017766179934636845/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3017766179934636845' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3017766179934636845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3017766179934636845'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2010/05/entity-value-object.html' title='Entity 與 Value Object的一點思考'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-8031778699927721856</id><published>2010-02-07T09:06:00.000-08:00</published><updated>2010-02-08T08:09:52.164-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>用四色原型改寫DDD中的範例模型</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;Domain Model Driven&lt;/span&gt;&lt;br /&gt;在Domain Driven Design的第164頁，上面有一個貨櫃運送的Domain Model Diagram&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/S3An1Z7lCrI/AAAAAAAAAO0/xZ3XyO3j288/s1600-h/DDD.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 286px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/S3An1Z7lCrI/AAAAAAAAAO0/xZ3XyO3j288/s400/DDD.jpg" alt="" id="BLOGGER_PHOTO_ID_5435888548683516594" border="0" /&gt;&lt;/a&gt;這張圖表達的是一個貨運公司的領域模型：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;每個貨櫃關連很多Cutomer角色，如運送者、接收人、付款人&lt;/li&gt;&lt;li&gt;貨櫃運送過程中會產生很多HandlingEvent，如上貨、卸貨、送達&lt;/li&gt;&lt;li&gt;HandlingEvent幾個組成一個CarrierMovement，由某Location到某Location&lt;br /&gt;&lt;/li&gt;&lt;li&gt;貨櫃抵達接收後，會產生一筆DeliveryHistory&lt;/li&gt;&lt;li&gt;運送過程可以改變行程，但最終必須符合DeliverySpecification規定的送達時間及目的地&lt;/li&gt;&lt;/ol&gt;有了這張圖，便可發揮DDD的理論進行設計。但我疑問的是，這張是怎麼推論出來的，只是翻遍全書也沒說明。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;四色原型&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;在學習四色原型漫長一段時間後，我終於有點領悟可以推論出以四色原型&lt;/span&gt;改寫過的模型。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/S3AspuxKmXI/AAAAAAAAAO8/y-q0Wy7smZE/s1600-h/DDD1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 267px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/S3AspuxKmXI/AAAAAAAAAO8/y-q0Wy7smZE/s400/DDD1.jpg" alt="" id="BLOGGER_PHOTO_ID_5435893845676693874" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;第一步先建出紅色的時間序例事件，CargoBook會有很多的CargoShipping，這個取代了原來的HandlingEvent。自關連的CargoShipping表示了一系列的事件。貨物抵達後，需要產生一個DeliveryHistory。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/S3Au-OxOdiI/AAAAAAAAAPE/lMWOs7r3_IQ/s1600-h/DDD2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 271px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/S3Au-OxOdiI/AAAAAAAAAPE/lMWOs7r3_IQ/s400/DDD2.jpg" alt="" id="BLOGGER_PHOTO_ID_5435896396887520802" border="0" /&gt;&lt;/a&gt;接下來推論角色，依據角色是一種狀態，以及一個物件可以扮演多個角色的原則，推論出這張圖。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/S3AxRca0t9I/AAAAAAAAAPM/JMn3MQjWU2Y/s1600-h/DDD3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 358px; height: 131px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/S3AxRca0t9I/AAAAAAAAAPM/JMn3MQjWU2Y/s400/DDD3.jpg" alt="" id="BLOGGER_PHOTO_ID_5435898925992425426" border="0" /&gt;&lt;/a&gt;重要的兩個綠色PPT&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/S3AyKos-ryI/AAAAAAAAAPU/SKBGTWdL3GI/s1600-h/DDD4.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 272px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/S3AyKos-ryI/AAAAAAAAAPU/SKBGTWdL3GI/s400/DDD4.jpg" alt="" id="BLOGGER_PHOTO_ID_5435899908542344994" border="0" /&gt;&lt;/a&gt;一系列的運送動作，可以組成一段行程，行程又由Location組成，這裏用了兩個藍色的Desc表達出這是同一類型的觀念。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/S3Ay845PAiI/AAAAAAAAAPc/KVJYZZ-zcsM/s1600-h/DDD5.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 371px; height: 240px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/S3Ay845PAiI/AAAAAAAAAPc/KVJYZZ-zcsM/s400/DDD5.jpg" alt="" id="BLOGGER_PHOTO_ID_5435900771882172962" border="0" /&gt;&lt;/a&gt;最後來考慮DeliverySpecification到底做了什麼事。總歸來說它就是一個規範，規範了抵達時間與地點，但可以有更「複雜」的使用。看過後面的Specification章節，我可以猜測應該有個IsOverDue的Method，協助判斷貨物到期了沒。所以我就想，在CargoShipping的產生過程中，應該也要有個PlugIn協助做這件事，然後也許我應該再開一個角色叫OverDueCargo吧。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/S3A24OFMlvI/AAAAAAAAAPs/Vbc2F8QOzzs/s1600-h/DDD6.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 269px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/S3A24OFMlvI/AAAAAAAAAPs/Vbc2F8QOzzs/s400/DDD6.jpg" alt="" id="BLOGGER_PHOTO_ID_5435905089716655858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;最終的成果&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;結尾&lt;/span&gt;&lt;br /&gt;四色原型的好用真是難以說明，歡迎有同好來討論。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-8031778699927721856?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/8031778699927721856/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=8031778699927721856' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8031778699927721856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8031778699927721856'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2010/02/ddd.html' title='用四色原型改寫DDD中的範例模型'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/S3An1Z7lCrI/AAAAAAAAAO0/xZ3XyO3j288/s72-c/DDD.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-5847609288941945403</id><published>2010-01-21T08:14:00.000-08:00</published><updated>2010-02-08T08:10:26.512-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>Moment-Interval深入思考</title><content type='html'>1、每個MI，都會包含一個時間或一段時間&lt;br /&gt;2、MI的連接，代表事件的執行順序&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/S13AqfSY9oI/AAAAAAAAAOU/c2O-YMHgfkY/s1600-h/MI1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 222px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/S13AqfSY9oI/AAAAAAAAAOU/c2O-YMHgfkY/s400/MI1.png" alt="" id="BLOGGER_PHOTO_ID_5430708561864357506" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;3、是一種Transaction Log&lt;br /&gt;&lt;ul&gt;&lt;li&gt;物件的增修改，都是一種Transaction，MI可以替其留下Log&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/S13BfmfS0pI/AAAAAAAAAOc/V3eeD9oUVcw/s1600-h/MI2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 382px; height: 132px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/S13BfmfS0pI/AAAAAAAAAOc/V3eeD9oUVcw/s400/MI2.png" alt="" id="BLOGGER_PHOTO_ID_5430709474330595986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;4、類似Transaction Script或DDD的Service概念&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Service是把無法歸類的邏輯集中到一個類別處理，並賦予Domain的概念。&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Transaction Script則是結構化設計的概念，將所有Domain物件該做的事皆放至一個類別來處理，所有的Domin物件都只有屬性，沒有方法。&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;以上兩種類別將會是Stateless&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;MI也是可以集中無法歸類的邏輯，但本身有時間序列及Log的概念，所以不會是Stateless&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/S13FlR80kwI/AAAAAAAAAOk/UrGdb9sN1DA/s1600-h/MI3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 364px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/S13FlR80kwI/AAAAAAAAAOk/UrGdb9sN1DA/s400/MI3.png" alt="" id="BLOGGER_PHOTO_ID_5430713969943024386" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-5847609288941945403?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/5847609288941945403/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=5847609288941945403' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/5847609288941945403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/5847609288941945403'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2010/01/moment-interval.html' title='Moment-Interval深入思考'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/S13AqfSY9oI/AAAAAAAAAOU/c2O-YMHgfkY/s72-c/MI1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-8326179032637228182</id><published>2010-01-19T19:29:00.000-08:00</published><updated>2010-02-08T08:10:56.656-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>Description的深入思考</title><content type='html'>1、用來描述性質的類別&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/S1cO4Ud-6gI/AAAAAAAAANk/-qyYHnzyjhw/s1600-h/desc1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 315px; height: 132px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/S1cO4Ud-6gI/AAAAAAAAANk/-qyYHnzyjhw/s400/desc1.png" alt="" id="BLOGGER_PHOTO_ID_5428824236548352514" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2、用來代表一組的PPT&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/S1cSVlRcmxI/AAAAAAAAAN0/pW17TaVYMG4/s1600-h/desc2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 296px; height: 274px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/S1cSVlRcmxI/AAAAAAAAAN0/pW17TaVYMG4/s400/desc2.png" alt="" id="BLOGGER_PHOTO_ID_5428828037810264850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;3、用來建立Knowledge Level&lt;br /&gt;Knowledge Level：系統類別可以分成兩種，一種是Operation Level，另一種就是Knowledge Level。Knowledge Level規範Operation Level的運作&lt;br /&gt;&lt;br /&gt;例如：我們習慣將特殊化現象時使用繼承&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/S1cYVQAjaSI/AAAAAAAAAOE/8yHaPgbLDZo/s1600-h/desc3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 307px; height: 266px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/S1cYVQAjaSI/AAAAAAAAAOE/8yHaPgbLDZo/s400/desc3.png" alt="" id="BLOGGER_PHOTO_ID_5428834629172029730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;但是這樣畫，更有彈性&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/S1cZXk5akxI/AAAAAAAAAOM/UPTmH49SqAA/s1600-h/desc4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 280px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/S1cZXk5akxI/AAAAAAAAAOM/UPTmH49SqAA/s400/desc4.png" alt="" id="BLOGGER_PHOTO_ID_5428835768650601234" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-8326179032637228182?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/8326179032637228182/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=8326179032637228182' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8326179032637228182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8326179032637228182'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2010/01/description.html' title='Description的深入思考'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/S1cO4Ud-6gI/AAAAAAAAANk/-qyYHnzyjhw/s72-c/desc1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3448991839142183369</id><published>2010-01-11T05:12:00.000-08:00</published><updated>2010-01-12T06:43:17.344-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>角色的深入思考</title><content type='html'>1、 一個PPT有多種角色&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/S0snNR1C8NI/AAAAAAAAAKs/OjWqg58brco/s1600-h/role1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 315px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/S0snNR1C8NI/AAAAAAAAAKs/OjWqg58brco/s320/role1.png" alt="" id="BLOGGER_PHOTO_ID_5425473285175570642" border="0" /&gt;&lt;/a&gt;2、可以分配與活動相關的屬性&lt;br /&gt;這句的意思就是區分一般屬性及與特定活動相關的屬性，這樣才能使PPT更為普遍，不會一直加開屬性。&lt;br /&gt;&lt;br /&gt;3、可用來表示狀態&lt;br /&gt;一般而言狀態常常是PPT的一個屬性。我覺得可以使用角色模式處理State Pattern，這樣也就不必擔心狀態是否會一直增加，增加程式的複雜度。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/S0yGI8nU3nI/AAAAAAAAAL8/HaO7WaWh3Jc/s1600-h/role1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 299px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/S0yGI8nU3nI/AAAAAAAAAL8/HaO7WaWh3Jc/s400/role1.jpg" alt="" id="BLOGGER_PHOTO_ID_5425859139342753394" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;4、Subsequent Role&lt;br /&gt;Subsequent Role是複雜的角色模式，要想勝任B的角色，必先當A角色，我喜歡這種圖形，雖然理論上較沒彈性，但清楚表達意涵。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/S0yGeMuwmCI/AAAAAAAAAMM/TU_CmRPcDQU/s1600-h/role3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 213px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/S0yGeMuwmCI/AAAAAAAAAMM/TU_CmRPcDQU/s400/role3.jpg" alt="" id="BLOGGER_PHOTO_ID_5425859504446150690" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;5、用來設計權限&lt;br /&gt;使用PersonRole做為所有Role的基礎類別，或系統角色的基礎類別，為每個角色建立權限。配合&lt;br /&gt;Subsequent Role就可以組出各種權限。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/S0yKVYuCtfI/AAAAAAAAANU/dnlZiVWwqZk/s1600-h/role4.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 573px; height: 210px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/S0yKVYuCtfI/AAAAAAAAANU/dnlZiVWwqZk/s400/role4.jpg" alt="" id="BLOGGER_PHOTO_ID_5425863751092057586" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;參考文獻：&lt;br /&gt;1、http://edn.embarcadero.com/jp/article/29678&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3448991839142183369?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3448991839142183369/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3448991839142183369' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3448991839142183369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3448991839142183369'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2010/01/blog-post.html' title='角色的深入思考'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/S0snNR1C8NI/AAAAAAAAAKs/OjWqg58brco/s72-c/role1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-8279741242410566816</id><published>2009-08-03T08:53:00.000-07:00</published><updated>2009-08-05T09:36:58.282-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>以四色原型改善資料庫設計之三-2</title><content type='html'>前面提到了角色的設計，我們來看另一種設計方法。這應該是Peter Coad大師在書上提過的作法，只是我沒看過書就是了。&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Role Object：&lt;/span&gt;&lt;br /&gt;Person類別不再實作所有角色的介面，而改成內部使用一個集合來擺放可能的角色。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;public class Person&lt;br /&gt;{&lt;br /&gt;private IList&lt;personrole&gt;&amp;lt;PersonRole&amp;gt; _roles = new List&lt;personrole&gt;&amp;lt;PersonRole&amp;gt;();&lt;br /&gt;&lt;br /&gt;public string Name{get;set;}&lt;br /&gt;public string Address{get;set;}&lt;br /&gt;public string Tel{get;set;}&lt;br /&gt;&lt;br /&gt;public void AddRole(PersonRole role)&lt;br /&gt;{&lt;br /&gt;_roles.Add(role);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public T RoleOf&lt;t&gt;&amp;lt;T&amp;gt;() where T:PersonRole&lt;br /&gt;{&lt;br /&gt;foreach(PersonRole role in _roles)&lt;br /&gt;{&lt;br /&gt;   if(role.HasType&lt;t&gt;&amp;lt;T&amp;gt;())&lt;br /&gt;   {&lt;br /&gt;       return (T)role;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return null;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/t&gt;&lt;/t&gt;&lt;/personrole&gt;&lt;/personrole&gt;&lt;/code&gt;&lt;/pre&gt;依據Matin Fowler大師的建議，替PersonRole加上HasType這個方法，日後我們的角色如果成長成一顆繼承樹時(Sequenal Roles)，就會很有用。例如專任教師、科任教師的父角色都是教師，而教師的父角色可能是教職員工，這裏就可以寫些判斷的方法。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;public abstract class PersonRole&lt;br /&gt;{&lt;br /&gt;public bool HasType&amp;lt;T&amp;gt;()&lt;br /&gt;{&lt;br /&gt;if(this is T)&lt;br /&gt;{&lt;br /&gt;   return true;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;   return false;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Customer與Employee就只要繼承PersonRole就好了&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;public class Customer : PersonRole&lt;br /&gt;{&lt;br /&gt;public string DeliverAddress{get;set;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Employee : PersonRole&lt;br /&gt;{&lt;br /&gt;public int MonthSalary{get;set;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;測試碼如下：&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;[Test]&lt;br /&gt;public void TestMakeCustomer()&lt;br /&gt;{&lt;br /&gt;Person person = new Person();&lt;br /&gt;&lt;br /&gt;Customer customer = new Customer();&lt;br /&gt;customer.DeliverAddress = "台北市忠孝東路";&lt;br /&gt;person.AddRole(customer);&lt;br /&gt;&lt;br /&gt;Customer customerRole = person.RoleOf&amp;lt;Customer&amp;gt;();&lt;br /&gt;&lt;br /&gt;Assert.IsNotNull(customerRole); &lt;br /&gt;Assert.AreEqual("台北市忠孝東路",customerRole.DeliverAddress);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestMakeEmployee()&lt;br /&gt;{&lt;br /&gt;Person person = new Person();&lt;br /&gt;&lt;br /&gt;Employee employee = new Employee();&lt;br /&gt;employee.MonthSalary = 40000;&lt;br /&gt;person.AddRole(employee);&lt;br /&gt;&lt;br /&gt;Employee employeeRole = person.RoleOf&amp;lt;Employee&amp;gt;();&lt;br /&gt;&lt;br /&gt;Assert.IsNotNull(employeeRole); &lt;br /&gt;Assert.AreEqual(40000,employeeRole.MonthSalary);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-8279741242410566816?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/8279741242410566816/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=8279741242410566816' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8279741242410566816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8279741242410566816'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/08/2.html' title='以四色原型改善資料庫設計之三-2'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-9193018726706500573</id><published>2009-07-23T18:53:00.001-07:00</published><updated>2009-08-09T18:55:43.241-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>關於類別圖的一些思考之三</title><content type='html'>&lt;span style="font-weight: bold;"&gt;自身關聯：&lt;br /&gt;&lt;/span&gt;自身關聯分成兩種，一種是一對多的自身關聯，一種是多對一的自身關聯，但在資料庫的設計上都是一樣的，每一筆資料多開出一個欄位，用來關聯同一資料表內的其他資料。自身關聯通常用來表示樹狀結構如組織圖、BOM表。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1對多：&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SnD4x4q5jlI/AAAAAAAAAJM/A-lK9phINJc/s1600-h/SelfRelation1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 241px; height: 132px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SnD4x4q5jlI/AAAAAAAAAJM/A-lK9phINJc/s400/SelfRelation1.png" alt="" id="BLOGGER_PHOTO_ID_5364060692107857490" border="0" /&gt;&lt;/a&gt;1對多通常是用來表示整體部分的關係，這不用多說。以這種方式取出的物件，還有一個好處，就是使用Composition Pattern的手法，對某個Org下所有子Org遍覽一次。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;多對1：&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SnD6anRknbI/AAAAAAAAAJU/ZiUj4OTTrFo/s1600-h/SelfRelation2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 323px; height: 159px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SnD6anRknbI/AAAAAAAAAJU/ZiUj4OTTrFo/s400/SelfRelation2.png" alt="" id="BLOGGER_PHOTO_ID_5364062491324489138" border="0" /&gt;&lt;/a&gt;看起來多對1就僅只在表示某些物件有關聯而已。&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;合併使用：&lt;/span&gt;&lt;br /&gt;很普遍的狀況，以一對多包含下層結點，多對一包含一個上層結點，典型的樹狀結構。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/Snm73Wj8j-I/AAAAAAAAAKM/6pm5pt8Ns9s/s1600-h/SelfRelation8.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 180px; height: 106px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/Snm73Wj8j-I/AAAAAAAAAKM/6pm5pt8Ns9s/s400/SelfRelation8.png" alt="" id="BLOGGER_PHOTO_ID_5366526990612205538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/Snm4EQ2J1LI/AAAAAAAAAJ8/U4cxC_9CAqo/s1600-h/SelfRelation6.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 205px; height: 160px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/Snm4EQ2J1LI/AAAAAAAAAJ8/U4cxC_9CAqo/s400/SelfRelation6.png" alt="" id="BLOGGER_PHOTO_ID_5366522814369748146" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;結點重複的畫法：&lt;/span&gt;&lt;br /&gt;所謂的結點重複，代表一顆樹中，組成的元素是會重複的，如下&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/Sn96Tmmfc5I/AAAAAAAAAKU/k7ulQ19MU6Q/s1600-h/SelfRelation9.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 216px; height: 185px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/Sn96Tmmfc5I/AAAAAAAAAKU/k7ulQ19MU6Q/s400/SelfRelation9.png" alt="" id="BLOGGER_PHOTO_ID_5368143758047015826" border="0" /&gt;&lt;/a&gt;如之前的文章所述，這時的Aggregation暗藏著多對多的訊息，所以就如此重繪。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/Sn992NFub7I/AAAAAAAAAKc/LzcaH17ra9c/s1600-h/SelfRelation10.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 199px; height: 262px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/Sn992NFub7I/AAAAAAAAAKc/LzcaH17ra9c/s400/SelfRelation10.png" alt="" id="BLOGGER_PHOTO_ID_5368147651029004210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;多對多：&lt;/span&gt;&lt;br /&gt;最近在思考這種關係如何表達&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/Snm58kE9YzI/AAAAAAAAAKE/0zA7byAeIxQ/s1600-h/SelfRelation7.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 149px; height: 137px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/Snm58kE9YzI/AAAAAAAAAKE/0zA7byAeIxQ/s400/SelfRelation7.png" alt="" id="BLOGGER_PHOTO_ID_5366524881116422962" border="0" /&gt;&lt;/a&gt;畫抽象一點，就是一個多對多的自身關聯。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SnD8d6F6xxI/AAAAAAAAAJc/F5INPMgdTms/s1600-h/SelfRelation3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 187px; height: 144px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SnD8d6F6xxI/AAAAAAAAAJc/F5INPMgdTms/s400/SelfRelation3.png" alt="" id="BLOGGER_PHOTO_ID_5364064746938746642" border="0" /&gt;&lt;/a&gt;如果是上列關係，倒可視為如下關係的簡化。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/SncEsevvpZI/AAAAAAAAAJs/uvolSv8q24I/s1600-h/SelfRelation5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 356px; height: 131px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/SncEsevvpZI/AAAAAAAAAJs/uvolSv8q24I/s400/SelfRelation5.png" alt="" id="BLOGGER_PHOTO_ID_5365762643249309074" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-9193018726706500573?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/9193018726706500573/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=9193018726706500573' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/9193018726706500573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/9193018726706500573'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/07/uml_23.html' title='關於類別圖的一些思考之三'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/SnD4x4q5jlI/AAAAAAAAAJM/A-lK9phINJc/s72-c/SelfRelation1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-2764745542474390273</id><published>2009-07-22T18:50:00.000-07:00</published><updated>2009-08-04T09:01:53.545-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>以四色原型改善資料庫設計之三-1</title><content type='html'>接下來我們繼續研究Supplier、Customer、Employee、Shipper的設計。我們就這麼假定，Employee就只能是Person，Customer可以是Person與Company，Supplier與Shipper則是只能是Company。當我們想使用繼承的觀念來處理這幾個主檔時，Custmer就會帶來很大的困擾。因為就概念上我們不能取出一個Customer，然後他的父類別居然是可變的。注意是可變的，並不是Customer同時是Person與Company的多重繼承觀念。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/Sm51iQMLvII/AAAAAAAAAJE/3vypNEQPcXQ/s1600-h/Role.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 129px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/Sm51iQMLvII/AAAAAAAAAJE/3vypNEQPcXQ/s400/Role.png" alt="" id="BLOGGER_PHOTO_ID_5363353437566909570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;這個問題稱之為Role問題，Customer、Supplier、Shipper是Company的角色，Customer、Employee是Person的角色。Peter Coad在他的書上提到了這個Pattern，但我只能在Matin Fowler的網站上看到示範的Code。&lt;br /&gt;Fowler所提的解法，我歸類為兩種，由於解法不同，資料庫的設計也就不同。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Role SubType：&lt;/span&gt;&lt;br /&gt;首先準備如下的介面&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;public interface IPerson&lt;br /&gt;{&lt;br /&gt;string Name{get;set;}&lt;br /&gt;string Address{get;set;}&lt;br /&gt;string Tel{get;set;}&lt;br /&gt;}&lt;br /&gt;public interface ICustomer : IPerson&lt;br /&gt;{&lt;br /&gt;string DeliverAddress{get;set;}&lt;br /&gt;}&lt;br /&gt;public interface IEmployee : IPerson&lt;br /&gt;{&lt;br /&gt;int MonthSalary{get;set;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;再準備如下的抽象類別及其實作&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;public abstract class PersonRole&lt;br /&gt;{&lt;br /&gt;public virtual string DeliverAddress&lt;br /&gt;{&lt;br /&gt;get{throw new ApplicationException("not implement");}&lt;br /&gt;set{throw new ApplicationException("not implement");}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public virtual int MonthSalary&lt;br /&gt;{&lt;br /&gt;get{throw new ApplicationException("not implement");}&lt;br /&gt;set{throw new ApplicationException("not implement");}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Employee : PersonRole&lt;br /&gt;{&lt;br /&gt;private int _monthSalary;&lt;br /&gt;public override int MonthSalary&lt;br /&gt;{&lt;br /&gt;get{return _monthSalary;}&lt;br /&gt;set{_monthSalary = value;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Customer : PersonRole&lt;br /&gt;{&lt;br /&gt;private string _deliverAddress;&lt;br /&gt;public override string DeliverAddress&lt;br /&gt;{&lt;br /&gt;get{return _deliverAddress;}&lt;br /&gt;set{_deliverAddress = value;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;Person類別就這麼寫：&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;public class Person : IPerson,IEmployee,ICustomer&lt;br /&gt;{&lt;br /&gt;private PersonRole _personRole;&lt;br /&gt;public string Name{get;set;}&lt;br /&gt;public string Address{get;set;}&lt;br /&gt;public string Tel{get;set;}&lt;br /&gt;&lt;br /&gt;public string DeliverAddress&lt;br /&gt;{&lt;br /&gt; get{return _personRole.DeliverAddress;}&lt;br /&gt; set{_personRole.DeliverAddress = value;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public int MonthSalary&lt;br /&gt;{&lt;br /&gt; get{return _personRole.MonthSalary;}&lt;br /&gt; set{_personRole.MonthSalary = value; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static IEmployee MakeEmployee()&lt;br /&gt;{&lt;br /&gt; Person person = new Person();&lt;br /&gt; person._personRole = new Employee();&lt;br /&gt; return person;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static ICustomer MakeCustomer()&lt;br /&gt;{&lt;br /&gt; Person person = new Person();&lt;br /&gt; person._personRole = new Customer();&lt;br /&gt; return person;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;測試代碼如下：&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestMakeEmployee()&lt;br /&gt;{&lt;br /&gt;IEmployee employee = Person.MakeEmployee();&lt;br /&gt;employee.MonthSalary = 40000;&lt;br /&gt;&lt;br /&gt;Assert.AreEqual(40000,employee.MonthSalary);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestMakeCustomer()&lt;br /&gt;{&lt;br /&gt;ICustomer customer = Person.MakeCustomer();&lt;br /&gt;customer.DeliverAddress = "台北市忠孝東路";&lt;br /&gt;&lt;br /&gt;Assert.AreEqual("台北市忠孝東路",customer.DeliverAddress);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-2764745542474390273?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/2764745542474390273/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=2764745542474390273' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/2764745542474390273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/2764745542474390273'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/07/blog-post_5860.html' title='以四色原型改善資料庫設計之三-1'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/Sm51iQMLvII/AAAAAAAAAJE/3vypNEQPcXQ/s72-c/Role.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-240022511341654114</id><published>2009-07-22T08:37:00.000-07:00</published><updated>2009-08-10T18:44:26.916-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>關於類別圖的一些思考之二</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;多對多：&lt;br /&gt;&lt;/span&gt;之前提到的association可以用來表達多對一，aggregation可以用來表達一對多，如果Method的責任就這麼指定，我覺得是合理的。但對於多對多的狀況，就必須另找答案。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/Smc4a6aJLwI/AAAAAAAAAIk/2-BLqf5tics/s1600-h/ClassDiagram2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 314px; height: 132px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/Smc4a6aJLwI/AAAAAAAAAIk/2-BLqf5tics/s400/ClassDiagram2.png" alt="" id="BLOGGER_PHOTO_ID_5361315916414529282" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;我們都了解多對多在資料庫是採用中介資料表來處理，但實際辨識上，卻可以想成是這種關係的簡化。如果是這種關係，我們自然可以很好推測Student那邊有AddStudentSubject()，而StudentSubject那邊有StudentSubject.GetStudentSubjectBySubject()這樣的Method。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/Smc5gW_Ao4I/AAAAAAAAAI0/1mhX-UU8l54/s1600-h/ClassDiagram3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 314px; height: 272px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/Smc5gW_Ao4I/AAAAAAAAAI0/1mhX-UU8l54/s400/ClassDiagram3.png" alt="" id="BLOGGER_PHOTO_ID_5361317109496324994" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;經過簡化後，我就在Student那邊加上AddSubject()，以及Student.GetStudentBySubject()。當然Subject那邊也可以加上Subject.GetSubjectByStudent。那為何不乾脆Subject那邊也加上AddStudent算了?我只能強調多對多就是上列關係的簡化，不當的雙向關聯，只會讓語意產生模糊。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/Smc84OcjCBI/AAAAAAAAAI8/oK-ZEwx38nY/s1600-h/ClassDiagram4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 119px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/Smc84OcjCBI/AAAAAAAAAI8/oK-ZEwx38nY/s400/ClassDiagram4.png" alt="" id="BLOGGER_PHOTO_ID_5361320818056038418" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;不明確的表示法：&lt;/span&gt;&lt;br /&gt;有時候會看見這種aggregation畫法，沒有標示多重性，會讓人誤解只是單純的一對多。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SoDMFieLoeI/AAAAAAAAAKk/_3ihtwyI4ck/s1600-h/ClassDiagram5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 317px; height: 132px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SoDMFieLoeI/AAAAAAAAAKk/_3ihtwyI4ck/s400/ClassDiagram5.png" alt="" id="BLOGGER_PHOTO_ID_5368515151350440418" border="0" /&gt;&lt;/a&gt;但事實上很明顯的，一個學生可以選擇多堂課，而一堂課也可以被不同學生選取啊，這分明是多對多的關係。這樣畫對UML來說完全是對的，但無論是對意義的傳達上，還是拿來設計資料庫，都是有問題的。最好還是標上多重性。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-240022511341654114?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/240022511341654114/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=240022511341654114' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/240022511341654114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/240022511341654114'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/07/blog-post_22.html' title='關於類別圖的一些思考之二'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cvihUH5Nlq8/Smc4a6aJLwI/AAAAAAAAAIk/2-BLqf5tics/s72-c/ClassDiagram2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-1126839775703134335</id><published>2009-07-14T08:15:00.000-07:00</published><updated>2009-07-29T19:08:42.364-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>以四色原型改善資料庫設計之二</title><content type='html'>&lt;h2 id="主檔"&gt;&lt;span style="font-weight: bold;"&gt;主檔：&lt;/span&gt;&lt;/h2&gt;原來資料庫中的主檔如下：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SmUZq5H1EpI/AAAAAAAAAIU/wJ06t3Sj7HI/s1600-h/Northwind3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 354px; height: 138px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SmUZq5H1EpI/AAAAAAAAAIU/wJ06t3Sj7HI/s400/Northwind3.png" alt="" id="BLOGGER_PHOTO_ID_5360719156133302930" border="0" /&gt;&lt;/a&gt;仔細看過他們的欄位，無非都是名稱、地址、電話，換句話說他們都是Party的一種，所以我們建立起一個共用的Party當成共同主檔。再來Party主檔之下，還可以再區分兩個繼承主檔，Person與Company。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SmUbD-WU_NI/AAAAAAAAAIc/ZanQKi5B3fE/s1600-h/Northwind4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 273px; height: 159px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SmUbD-WU_NI/AAAAAAAAAIc/ZanQKi5B3fE/s400/Northwind4.png" alt="" id="BLOGGER_PHOTO_ID_5360720686544649426" border="0" /&gt;&lt;/a&gt;使用資料庫實現繼承的方法有三種，這裏我只想表達出概念如此，Party與Person或Company都是1對0..1的關係。這樣整理之後，就會發現Supplier、Shipper、Employee、Customer剩不了什麼自己的欄位了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-1126839775703134335?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/1126839775703134335/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=1126839775703134335' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/1126839775703134335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/1126839775703134335'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/07/blog-post_14.html' title='以四色原型改善資料庫設計之二'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cvihUH5Nlq8/SmUZq5H1EpI/AAAAAAAAAIU/wJ06t3Sj7HI/s72-c/Northwind3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3034944561414211114</id><published>2009-07-09T18:22:00.000-07:00</published><updated>2009-07-29T01:17:35.204-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>關於類別圖的一些思考之一</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;Association(關係)，Aggregation(聚合)，Composition(組合)：&lt;/span&gt;&lt;br /&gt;思考了一下三者的關聯，網路上找不到太明確的解釋，只好自己下定義。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;association：關聯的兩方都是單獨的個體。一的那方不保有多的那方的集合，多的那方有一的參考。當一的那方想取得多的那方的物件時，應該透過多的那方的Method進行讀取，如Building.GetBuildingsByOwner(Owner)。&lt;/li&gt;&lt;li&gt;aggregation：代表兩方有整體與部分的關係。最明顯的，一的那方會有集合保有多的那方的物件集合。就外部來看，想取得多的那方的物件，也只能透過一的那方的Method。所以會是order.AddDetail(OrderDetail)與order.OrderDetails[2]。&lt;/li&gt;&lt;li&gt;composition：關係與aggregation一樣，一般而言指的是物件的內部集合，加不進去，也取不到的關係，可以說非常少見。&lt;/li&gt;&lt;/ol&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/SlvxLrRi07I/AAAAAAAAAIM/ZU1CttmQ7U4/s1600-h/UML1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 284px;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/SlvxLrRi07I/AAAAAAAAAIM/ZU1CttmQ7U4/s320/UML1.png" alt="" id="BLOGGER_PHOTO_ID_5358141364584502194" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3034944561414211114?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3034944561414211114/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3034944561414211114' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3034944561414211114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3034944561414211114'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/07/uml.html' title='關於類別圖的一些思考之一'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cvihUH5Nlq8/SlvxLrRi07I/AAAAAAAAAIM/ZU1CttmQ7U4/s72-c/UML1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-4385983105736542681</id><published>2009-07-02T23:32:00.000-07:00</published><updated>2009-08-03T18:30:47.950-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開發流程'/><title type='text'>系統分析設計相關技能概論</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SlFZ1nrtkHI/AAAAAAAAAHk/gCbY8T1-_As/s1600-h/SoftDevelop.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 414px; height: 269px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SlFZ1nrtkHI/AAAAAAAAAHk/gCbY8T1-_As/s320/SoftDevelop.png" alt="" id="BLOGGER_PHOTO_ID_5355160209640493170" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;需求收集&lt;/span&gt;&lt;span style="font-size:130%;"&gt;：&lt;/span&gt;&lt;br /&gt;其目的是在替需求建立文字性的描述，以一種連鎖的關連組織需求。通常還帶有規範功能粒度的目的。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Use Case：這步驟算是最為知名，也最容易為人誤解。將它當成OOA的必要技術。很可惜，它跟OO一點關連也沒有，甚至也不能算分析的一種。Use Case的優點在於可以明確的記錄使用者與系統的互動，依據RUP的流程，這就是系統開發與專案管理的基礎。但缺點在於文字並不是溝通以及建立概念的好工具，在這一階段容易與使用者耗費過久的時間確定文字的內容，這點是相當不利的。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;User Story：做為XP的需求收集工具，自然崇尚簡單，User Story間沒有太嚴謹的組織關連，也不必要精確的記錄每個步驟。通常只是一段散文式的情節。缺點也在於它的簡單含糊，所以事後得花更多的時間與使用者確認，不過這也符合XP快速開發的意思，如果不會愈改愈慘的話。&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;系統分析：&lt;/span&gt;&lt;br /&gt;分析的目的在將蒐集來的資訊重新組織，以便更能進入程式碼的狀態。所以這個階段是實際編程的起步，應該融合了領域知識的概念還有程式的抽象概念。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Domain Model：以類別圖描述業務邏輯，就是這種分析法的宗旨。建立Domain Model是一項晦澀難明的事，相關的書籍只有兩大天書Java Modeling With Color UML與Analysis Pattern。建立Domain Model通常沒有需求收集階段，基本假設就是拿Domain Model與客戶面對面溝通，而不是先使用文字記錄。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;四色原型：就是由Java Modeling With Color UML所提的，一組接近人類思維表達法(人地物、事件、角色、描述)，建立模型。&lt;/li&gt;&lt;li&gt;Analysis Pattern：蒐集了大量OO建模的技巧，粗看相當頊碎，而且沒有歸納出一套推理法則。不過最近我在畫Domain Model時，常常是先用四色原型勾勒出大概，再用Analysis Pattern進行下一步的設計考量。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;CRC卡分析：XP的開發人員依據User Story，利用CRC卡(一種像類別圖的卡片)，直接進行程式責任的指定，沒有一套理論教導我們如何進行這項工作，也沒有理論告訴我們該做到什麼程度是合適的。所以我只能將這一步驟擺在分析與設計之間。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;文本分析&amp;amp;強固圖&amp;amp;循序圖：這是RUP開發的流程，我順便補上了ICONIX流程所說的強固圖&lt;/li&gt;&lt;ul&gt;&lt;li&gt;文本分析：將還在文字階段的Use Case進行名詞剖析，做出靜態的類別圖(無方法)。&lt;/li&gt;&lt;li&gt;強固圖分析：上一步的類別圖會轉成Entity，Use Case的流程轉成一個接一個的Control，UI轉成Boundary，畫出Robustness Diagram。&lt;/li&gt;&lt;li&gt;循序圖分析：將行為加到Control上面，畫出Sequence Diagram。&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;ProtoType分析：這裏我只想強調，ProtoType就只是在分析UI的行為，沒法取代前述的分析方法。其實我比較認同應該設立業務分析師與UI分析師兩種職位。&lt;/li&gt;&lt;li&gt;BDD&amp;amp;DSL：對這兩種全新的分析方法，我還在了解中。&lt;/li&gt;&lt;li&gt;DFD：對於這個有點年紀的分析方法，我大概沒時間了解了。&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;系統設計：&lt;/span&gt;&lt;br /&gt;設計有兩種職位，一種是延續分析的工作，將業務邏輯設計的更具擴充性、與維護性。一種則是純技術的好手，負責規畫非功能需求的解決方案。我列出的技能都是屬於第一種。&lt;br /&gt;Martin Flowler有說到業務邏輯的設計方式有三，一是Domain Model，二是Transaction Script，三是Table Model。個人覺得設計方式的不同，也連帶的影響了分析的方式。順著Domain Model的分析便流到了Domain Model的設計，順著RUP分析的便流到了Microsoft TLSA。&lt;ol&gt;&lt;li&gt;Domain Model Driven Design：是一本Domain Model設計方法的書籍，且有很大的影響力。個人覺得DDD的位置介於分析與設計之間，有點像JMCU式規範業務類別的種類，又有點像Enteripse Pattern式的列出最佳設計原則。DDD目前已經有不少的現成框架，可以一氣呵成的完成Domain Model式的開發方法。&lt;/li&gt;&lt;li&gt;Microsoft TLSA：相信很多人不清楚這是什麼東西，簡單言之它就是PetShop4的示範框架(Three Layer Service Application應該吧)。就是WindowWorkFlow包Business Component，Business Component包Business Entity，這種實作方式被Matin Fowler大師說是一種貧血模型，並不能說是真正的OO系統。但我又為何把RUP分析的結果直接導入這個框架?因為如果深思一番，你就會發現Business Component很像Control，Business Entity很像Entity，這種緊密的連續思路，當然要把這兩者扯在一起。所以RUP是OO的開發方法嗎?我只能說，可以是，也可以不是。&lt;/li&gt;&lt;li&gt;ORM：從趨勢上來看，這種東西快成必需品，也許很快新人工程師就會忘了這世界上有DataSet這回事。&lt;/li&gt;&lt;li&gt;IOC、AOP：我想會再寫一篇文來介紹這兩種觀念，IOC是Stragery模式的實務應用方式，AOP是Decorator模式的延伸應用。&lt;/li&gt;&lt;li&gt;MVC、MVP：這世界總是會有人強調寫UI沒這些架構也活的好好的，若這麼說寫程式確實不須這麼多的理論，只要有一顆清楚的腦袋。所以發明架溝的人，主要是讓腦子不那麼清楚的工程師可以有個方向。&lt;/li&gt;&lt;li&gt;Design Pattern：這本書的重要就不多說了，就算你23個Pattern，用不到三分之一或五分之一，也請謹記基本的OOD守則，SRP(單一責任)、OCP(開放封閉)、LSP、DIP(依賴反轉)、(ISP)介面分離。&lt;/li&gt;&lt;li&gt;Enteripse Pattern：光看Design Pattern會讓人覺得太學術，那Enterprise Pattern就好比基本物理對上應用物理的，針對商業系統所歸納出的一連串設計原則。&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-4385983105736542681?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/4385983105736542681/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=4385983105736542681' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4385983105736542681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4385983105736542681'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/07/blog-post_02.html' title='系統分析設計相關技能概論'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/SlFZ1nrtkHI/AAAAAAAAAHk/gCbY8T1-_As/s72-c/SoftDevelop.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-6044074504646563917</id><published>2009-07-02T09:19:00.000-07:00</published><updated>2009-07-14T08:14:38.684-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>以四色原型改善資料庫設計之一</title><content type='html'>&lt;h2 id="交易檔"&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;交易檔&lt;/span&gt;&lt;/h2&gt; &lt;p&gt; 交易檔的判斷方式有三： &lt;/p&gt; &lt;ol&gt;&lt;li&gt;資料具有時間性 &lt;/li&gt;&lt;li&gt;大部分都是不斷Append，很少修改 &lt;/li&gt;&lt;li&gt;兩個主檔之間的關聯檔 &lt;/li&gt;&lt;/ol&gt;&lt;h2 id="主檔"&gt;&lt;span style="font-size:130%;"&gt;主檔&lt;/span&gt;&lt;/h2&gt; &lt;p&gt; 主檔的資料是特定的，具體的。例如各種人、事、物。 &lt;/p&gt; &lt;ol&gt;&lt;li&gt;繼承：當很多的主檔部分屬性相同之時，可以考慮把相同的屬性取出來變成一個主檔。例如Person與Company都有共同的屬性名稱、住址、電話，可以另外抽出一個Party主檔。 &lt;/li&gt;&lt;/ol&gt;&lt;h2 id="角色檔"&gt;&lt;span style="font-size:130%;"&gt;角色檔&lt;/span&gt;&lt;/h2&gt; &lt;p&gt; 角色檔是主檔參予交易檔的方式。主檔參予交易檔後，可能會衍生出更多的欄位，所以可以設定一個角色檔來放置這些資料。 &lt;/p&gt; &lt;h2 id="描述檔"&gt;&lt;span style="font-size:130%;"&gt;描述檔&lt;/span&gt;&lt;/h2&gt; &lt;p&gt; 描述檔的內容是固定的，例如台灣有16個縣，360個鄉鎮，以及為數眾多的路名，這些系統外的資訊可以當成描述檔。 &lt;/p&gt;&lt;h2 id="接下來我以Northwind資料庫做示範"&gt;&lt;span style="font-size:130%;"&gt;接下來我以Northwind資料庫做示範：&lt;/span&gt;&lt;/h2&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SkzenMjgnHI/AAAAAAAAAG8/Gkl9lDTn-Jg/s1600-h/Northwind1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SkzenMjgnHI/AAAAAAAAAG8/Gkl9lDTn-Jg/s320/Northwind1.png" alt="" id="BLOGGER_PHOTO_ID_5353898822003104882" border="0" /&gt;&lt;/a&gt;這張圖描述了幾個點：  &lt;ol&gt;&lt;li&gt;有一份Order，包含多個明細，每個明細關連一個Product &lt;/li&gt;&lt;li&gt;Order牽涉到三種資料，Employee、Customer、Shipper &lt;/li&gt;&lt;li&gt;Product有一個歸類的Category，以及它的Supplier &lt;/li&gt;&lt;li&gt;Employee有很多的Territories，Territories可以再被歸類成Region &lt;/li&gt;&lt;li&gt;Customer就恕在下眼拙，看不出其意義&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt; 以上我就不像從前還得講述什麼一對多，多對多，三個正規化的基本常識。而純粹就我提出的四點，重新配置這些檔案。&lt;br /&gt;&lt;/p&gt;&lt;h2 id="交易檔1"&gt;&lt;span style="font-size:130%;"&gt;交易檔&lt;/span&gt;&lt;/h2&gt; &lt;ol&gt;&lt;li&gt;當然第一個就是抽離出交易檔，原本的資料表，可以很快的鑑別出Order還有其明細檔OrderDetail是為交易檔。但仔細看 Order檔的欄位，卻發現有三個與時間相關的欄位OrderDate(訂購日期)、RequireDate(到貨日期)、ShippedDate(出貨 日期)。以交易檔第一條款，我再拆出一個Shipment檔。雖然Order對Shipment是1對1的關係，但FK絕對是落在Shipment上。 &lt;/li&gt;&lt;li&gt;再仔細觀察Product既然有Supplier，如果假設Product可以更換Supplier，亦即時間區段不同 Product與Supplier的關係也會不同。所以我分出一個SupplierProduct，關連Supplier與Product，這合乎交易檔 的第一和第三法則。 &lt;/li&gt;&lt;li&gt;這時似乎與OrderDetail關連的，應該是決定了Supplier之後的SupplierProduct。使用SuppierProduct關連OrderDetail，會讓Product與Supplier的責任更乾淨。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;再研究EmployeeTerritories，它符合第三法則，彷彿具有時間性質，但卻不符合第二法則。Employee可能不同時期的責任州不同，卻沒有一直Append的必要，所以這個檔就不設成交易檔。&lt;/li&gt;&lt;/ol&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SlvlN8vm69I/AAAAAAAAAIE/qDgtOBdLKb8/s1600-h/Northwind2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 105px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SlvlN8vm69I/AAAAAAAAAIE/qDgtOBdLKb8/s320/Northwind2.png" alt="" id="BLOGGER_PHOTO_ID_5358128209494207442" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-6044074504646563917?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/6044074504646563917/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=6044074504646563917' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6044074504646563917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6044074504646563917'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/07/blog-post.html' title='以四色原型改善資料庫設計之一'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/SkzenMjgnHI/AAAAAAAAAG8/Gkl9lDTn-Jg/s72-c/Northwind1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3475993438251516284</id><published>2009-03-24T08:33:00.000-07:00</published><updated>2009-03-24T08:58:20.101-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>會議室預約的四色原型範例</title><content type='html'>&lt;span style="font-size:130%;"&gt;需求&lt;/span&gt;&lt;a title="Link to this section" href="http://localhost:8000/New_Martian_Chronicles/wiki/Modeling_In_Color_3#%E9%9C%80%E6%B1%82" class="anchor"&gt;&lt;br /&gt;&lt;/a&gt; &lt;ol&gt;&lt;li&gt;有 20 間會議室可供預約 &lt;ol class="loweralpha"&gt;&lt;li&gt;基本設備不同 &lt;/li&gt;&lt;li&gt;可容納人數不同 &lt;/li&gt;&lt;li&gt;可預約時段為 08:30~20:00, 以 15 分鐘為單位 &lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;有 8 套投影機可供運用 &lt;ol class="loweralpha"&gt;&lt;li&gt;預約會議室成功且會議室沒有安裝投影機, 才能預約 &lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;預約時, 須記錄與會人數、會議主題、時段、預約者姓名、 部門、職稱、聯絡資訊等 &lt;/li&gt;&lt;li&gt;會議室皆被預約時, 使用者可要求加入先進先出的排隊名單 &lt;/li&gt;&lt;li&gt;取消預約時, 系統會依先進先出通知排隊者 &lt;/li&gt;&lt;li&gt;使用者可查詢會議室使用情形 &lt;/li&gt;&lt;li&gt;管理者可調閱會議室使用紀錄&amp;amp;報表 &lt;/li&gt;&lt;/ol&gt;&lt;h2 id="概念"&gt;&lt;span style="font-size:130%;"&gt;概念&lt;/span&gt;&lt;/h2&gt;這個解答是從彩色UML的第60頁做為基礎，再稍加變化得來的。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/Scj-EMm5nAI/AAAAAAAAAF0/ZLdLxvZDYeM/s1600-h/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%84.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 464px; height: 271px;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/Scj-EMm5nAI/AAAAAAAAAF0/ZLdLxvZDYeM/s320/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%84.jpg" alt="" id="BLOGGER_PHOTO_ID_5316778708168186882" border="0" /&gt;&lt;/a&gt;&lt;p&gt; &lt;/p&gt;&lt;ol&gt;&lt;li&gt;所謂的會議室預約、投影機預約，可以對應是書中的Facility Use。 &lt;/li&gt;&lt;li&gt;會議室與投影機是可識別的單位，各需要一個綠色的類別。其中會議室可能有一個投影機。 &lt;/li&gt;&lt;li&gt;依據四色原則，綠色的Place、Thing要加入紅色的moment-interval，最好要有黃色的角色，所以增加使用中的會議室、使用中的投影機。 &lt;/li&gt;&lt;li&gt;預約者應該對應一個綠色的Party，可以由綠色的Party查出預約者姓名、 部門、職稱、聯絡資訊。 &lt;/li&gt;&lt;li&gt;第一個流程是請求活動預約，增加預約項目。 &lt;/li&gt;&lt;li&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/Scj-jUeJY7I/AAAAAAAAAF8/k1bbcxEB97k/s1600-h/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%840.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 246px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/Scj-jUeJY7I/AAAAAAAAAF8/k1bbcxEB97k/s320/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%840.jpg" alt="" id="BLOGGER_PHOTO_ID_5316779242854900658" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;          再來可以透過會議室類別，查出可用的會議室，利用使用中的會議室類別，查出指定的時段內，沒有被預約使用的會議室。&lt;/li&gt;&lt;li&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/Scj_J4iNIZI/AAAAAAAAAGM/Mh-SVyvPoxo/s1600-h/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%841.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 188px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/Scj_J4iNIZI/AAAAAAAAAGM/Mh-SVyvPoxo/s320/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%841.jpg" alt="" id="BLOGGER_PHOTO_ID_5316779905370628498" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;然後請求會議室預約，傳入使用中的會議室及時段，產生會議室預約資料，還有請求會議室使用，以產生預估的會議室使用資料。 &lt;/li&gt;&lt;li&gt;由於會議室可能事先安裝投影機，所以請求會議室使用後，必須查出該使用中的會議室，是否有投影機，若有應該請求投影機使用，加入預估的投影機使用資料。 &lt;/li&gt;&lt;li&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/Scj-_3iTvAI/AAAAAAAAAGE/0rWOe2BXuqo/s1600-h/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%842.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 421px; height: 202px;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/Scj-_3iTvAI/AAAAAAAAAGE/0rWOe2BXuqo/s320/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%842.jpg" alt="" id="BLOGGER_PHOTO_ID_5316779733303933954" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;投影機的預估類似會議室預估。 &lt;/li&gt;&lt;li&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/Scj_vnL2kyI/AAAAAAAAAGU/IhL54GlDO2c/s1600-h/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%843.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 140px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/Scj_vnL2kyI/AAAAAAAAAGU/IhL54GlDO2c/s320/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%843.jpg" alt="" id="BLOGGER_PHOTO_ID_5316780553548501794" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;列出先進先出的清單，可在預約時給定優先權，排序出資料。 &lt;/li&gt;&lt;li&gt;然後根據需求，時段是一個共通的資料，利用藍色來建立使用時段描述。 &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3475993438251516284?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3475993438251516284/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3475993438251516284' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3475993438251516284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3475993438251516284'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2009/03/blog-post.html' title='會議室預約的四色原型範例'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cvihUH5Nlq8/Scj-EMm5nAI/AAAAAAAAAF0/ZLdLxvZDYeM/s72-c/%E6%9C%83%E8%AD%B0%E5%AE%A4%E9%A0%90%E7%B4%84.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-6243744503471640898</id><published>2008-12-27T11:50:00.000-08:00</published><updated>2009-01-04T05:07:15.668-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>OOA雜想曲之一</title><content type='html'>話說有位自命不凡的工程師，在讀完眾多OOA的書籍後，自認為已掌握個中精要，便向老闆毛遂自薦，要為公司開發不同的領域的產品。老闆心想：年輕人有夢想是不錯，但什麼OOA、領域建模有這麼神奇嗎?便對工程師說：這麼吧，我有個朋友開了飲料店，正要擴充營運，需要一套系統。這件事就委任你去跟他了解需求吧。工程師答是，心想：先來溫習一下彩色UML，與Analysis Pattern，看看有沒有相關的領域模型。&lt;br /&gt;老闆的朋友：我需要一套系統，功能與畫面就去參考別家的產品，下次來時給我一些畫面，再來討論。然後，就急忙忙的走了。工程師當場腦子僵成一塊。回來立刻向老闆報告，不幹了。老闆就說：自古以來就是要先決定畫面與功能，分析師不就去談這些，有什麼不對勁。工程師很低調的回答道：不了解飲料店每日的工作，要怎麼分析一個系統。我連賣珍珠奶茶的流程也不清楚，怎麼可能知道要有幾個畫面供客戶使用。就算給我看過別的產品的畫面，但支撐這些畫面的流程，我也不清楚。老闆嘆道：以前就是這麼幹的，你怎麼問題那麼多。工程師心想：難怪公司的系統不但難維護，而且Bug又多又難處理。老闆道：好吧，我幫你聯絡他們店裏的一些人，你想問什麼，就僅量去問。&lt;br /&gt;飲料店小妹：賣飲料就是做好收錢，有什麼流程。工程師：呃，那我們就來討論飲料，你們店的飲料有幾種?小妹：有健康茶、調味茶、奶茶、花茶還有拿鐵。便問：妳說飲料有這些類，但有什麼不同呢?小妹：健康茶就是什麼也不加啊。調味茶就會加一些調味料。奶茶就是奶精加茶。花茶是茶葉混一些乾燥的植物。拿鐵就是茶加牛奶。對了!我們健康茶、調味茶、奶茶都可以加點配料。所謂配料就是珍珠、椰果、布丁，那個你看我們的產品目錄都有寫。工程師又問：那大小杯怎麼分。小妹回道：我們有三種Size，大杯700cc，中杯500cc，小杯250cc，不過小杯只有拿鐵有用喔。工程師回家後，翻遍所有書冊，得出以下圖形。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SWCzcxHBjlI/AAAAAAAAAFk/mjwy9k-viHw/s1600-h/%E9%A3%B2%E6%96%99%E5%BA%971.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 238px;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SWCzcxHBjlI/AAAAAAAAAFk/mjwy9k-viHw/s320/%E9%A3%B2%E6%96%99%E5%BA%971.jpg" alt="" id="BLOGGER_PHOTO_ID_5287423269333470802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;飲料指的是一杯杯賣出去的飲料，飲料品項指的是產品項目(阿里山綠茶、珍珠奶茶…)，品項目錄就是小妹指的健康茶、調味茶，容量指的是大中小。每杯飲料都有一些添加物，添加物的品項就是珍珠、百香果濃縮汁之類的，添加物目錄是指調味類還是附加類…。然後飲料與添加物的品項之間有點關聯，例如拿鐵不能加珍珠之類的。添加物的單位，是看加一匙還是加一杯。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-6243744503471640898?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/6243744503471640898/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=6243744503471640898' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6243744503471640898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6243744503471640898'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/12/ooa.html' title='OOA雜想曲之一'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/SWCzcxHBjlI/AAAAAAAAAFk/mjwy9k-viHw/s72-c/%E9%A3%B2%E6%96%99%E5%BA%971.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3326297205160926387</id><published>2008-08-07T07:55:00.000-07:00</published><updated>2008-08-07T08:06:23.365-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>NPetShop中Category的四色原型分析</title><content type='html'>&lt;span style="font-weight: bold;"&gt;NPetShop&lt;br /&gt;&lt;/span&gt; 首先來看NetShop上本來的設計，Category的下一層是Product,Product的下一層是Item，看來沒有變動的必要。比較奇特的是，在Item上多出一個Quanity以及Currency。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SJsNZp53jXI/AAAAAAAAAD0/BhmNLWXyFY8/s1600-h/Category1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SJsNZp53jXI/AAAAAAAAAD0/BhmNLWXyFY8/s320/Category1.jpg" alt="" id="BLOGGER_PHOTO_ID_5231790126517423474" border="0" /&gt;&lt;/a&gt; &lt;span style="font-weight: bold;"&gt;重新分析&lt;br /&gt;&lt;/span&gt; 第一個先把Item當成綠色的Thing，Product以及Category當成藍色的Description。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SJsNwweffcI/AAAAAAAAAD8/3TOvZe0jMAE/s1600-h/Category2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SJsNwweffcI/AAAAAAAAAD8/3TOvZe0jMAE/s320/Category2.jpg" alt="" id="BLOGGER_PHOTO_ID_5231790523418639810" border="0" /&gt;&lt;/a&gt;我認為綠色的，就是一個追蹤的個體，所以Quantity不該出現在這裏。再者UnitPrice與ListPrice，如果我的理解沒有錯誤， UnitPrice是商品的預計價格，而ListPrice才是要出售的價格。所以UnitPrice放在Product，ListPrice放在 Item。加上Quantity的Analysis Pattern，讓商品的價格可以國際化。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SJsONVoxFcI/AAAAAAAAAEE/b0NC-Rg6ypk/s1600-h/Category3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SJsONVoxFcI/AAAAAAAAAEE/b0NC-Rg6ypk/s320/Category3.jpg" alt="" id="BLOGGER_PHOTO_ID_5231791014430184898" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;既然綠色的代表一隻隻的寵物，所以加上IsSolid來分辨是否售出。Product也加上一個方法CalAvailableQty()，這樣也能算出某種商品的數量。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SJsOnnZ4mCI/AAAAAAAAAEM/IFz4cfscz5s/s1600-h/Category4.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SJsOnnZ4mCI/AAAAAAAAAEM/IFz4cfscz5s/s320/Category4.jpg" alt="" id="BLOGGER_PHOTO_ID_5231791465876199458" border="0" /&gt;&lt;/a&gt; 最後考慮Supplier，我一直認為它是綠色的。固然它可以是Party，在某個訂貨服務扮演一個供應商的角色。但這個廠商Party似乎在整個系統，找不出還能在其他服務中，扮演更多的角色。所以我就把它當然是一個綠色，繼承自Party。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SJsO24D6EiI/AAAAAAAAAEU/tL9RoEjpN5E/s1600-h/Category5.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SJsO24D6EiI/AAAAAAAAAEU/tL9RoEjpN5E/s320/Category5.jpg" alt="" id="BLOGGER_PHOTO_ID_5231791728045462050" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3326297205160926387?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3326297205160926387/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3326297205160926387' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3326297205160926387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3326297205160926387'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/08/npetshopcategory.html' title='NPetShop中Category的四色原型分析'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/SJsNZp53jXI/AAAAAAAAAD0/BhmNLWXyFY8/s72-c/Category1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-2110510997062103491</id><published>2008-07-13T03:55:00.000-07:00</published><updated>2008-07-21T22:40:15.218-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>NPetShop中Account的四色原型分析</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言：&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;.NET界的PetShop有兩款，一款是微軟出的PetShop，目前到4.0。一款是IBatis.NET出的NPetShop。NPetShop出的，比較符合OO的精神，適合拿做為四色原型分析的範例。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Accounts：&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;這次就從Accounts下的類別，重新分析。原來的設計是這樣的。&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Account與Address，一個Account連結一個Address。Account代表的當然是會員，至於Address代表地址。&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SHng5Dt3wiI/AAAAAAAAACc/rhpIZuE0T5Q/s1600-h/Accounts1.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SHng5Dt3wiI/AAAAAAAAACc/rhpIZuE0T5Q/s320/Accounts1.jpg" alt="" id="BLOGGER_PHOTO_ID_5222452513767670306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;   來考慮Account，讀過四色原型分析都知道，Party是一個重要的原型，泛指所有的人員組織，第一個想法就是建立一個Party來取代 Account。再來Account與Party不可能是等值的觀念。能參加購物的，就假定只有會員(Member)。Member與Party也不是等 值的觀念，Member只是Party的子集。那Account與Member的觀念等值嗎?有時是等值，有時不等值。如果一個會員一組帳號，那就是等 值。如果一個會員擁有多組帳號，那就不等值。不如把這個觀念拆開獨立。&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SHnhOBpP8CI/AAAAAAAAACk/1j6tvL7PeXc/s1600-h/Accounts2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SHnhOBpP8CI/AAAAAAAAACk/1j6tvL7PeXc/s320/Accounts2.jpg" alt="" id="BLOGGER_PHOTO_ID_5222452873988665378" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;再來考慮Address，我以為它是一個Value Object，至少在這個系統是。住址對像我這種租屋的來說，有10幾個人用跟我相同的住址。當我離開這間公寓後，住址還是在原處。住址當然不會重覆，但 在這個系統人員是Entity，那住址也只好變成Value Object，象徵屬性不會異動及無唯一性的特質。每個Party有一個Address，是這個系統的需求。&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SHnhfInRf5I/AAAAAAAAACs/MeNJNuJyNcY/s1600-h/Accounts3.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SHnhfInRf5I/AAAAAAAAACs/MeNJNuJyNcY/s320/Accounts3.jpg" alt="" id="BLOGGER_PHOTO_ID_5222453167917203346" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;在為這個系統打上顏色時，第一Party顯然是綠色，第二Accunt也是綠色，第三Address是藍色。那Member是綠色嗎?它繼承了 Party?可是就另一個方面它也可以說是扮演，這樣彈性比較大。如果說是是扮演，就可以視系統的狀況，隨時改變角色，以接近程式的術語，就是以合成取代 繼承。然後也可以同時扮演多種角色。所以我把Member改成Member的概念，也就是黃色。&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SHnhws2v7MI/AAAAAAAAAC0/jhHxmJc8pdM/s1600-h/Accounts4.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SHnhws2v7MI/AAAAAAAAAC0/jhHxmJc8pdM/s320/Accounts4.jpg" alt="" id="BLOGGER_PHOTO_ID_5222453469703564482" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-2110510997062103491?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/2110510997062103491/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=2110510997062103491' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/2110510997062103491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/2110510997062103491'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/07/npetshopaccount.html' title='NPetShop中Account的四色原型分析'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/SHng5Dt3wiI/AAAAAAAAACc/rhpIZuE0T5Q/s72-c/Accounts1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-5766411422106698738</id><published>2008-06-09T18:49:00.000-07:00</published><updated>2008-08-07T07:50:19.341-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>IBatis.NET在ORM的簡單應用</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;前言：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;IBatis.NET的功用，較之nHibernate實在相差甚遠。它只是協助你把查出來的資料，組成物件而已。而查詢資料的SQL，很抱歉，請自己設 計。較之nHibernate一切包的好好的，理論上只要設計好物件，再透過nH產生的資料庫，是不必管SQL語法的長像的。兩者的優缺點是看各人的需求 的，如果資料庫沒有設計的夠OO，用IBatis是比較靈活的。當然，如果從頭到尾都是OO思考，用nH是可以享受設計一次，觀念一致的系統。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;系統需求：&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;先去下載&lt;a class="ext-link" href="http://ibatis.apache.org/"&gt;&lt;span class="icon"&gt;http://ibatis.apache.org/&lt;/span&gt;&lt;/a&gt;下載最新版的DataMapper，我下載的是IBatisNet.DataMapper-bin-1.6.1.zip，把它解開。 &lt;/li&gt;&lt;li&gt;示範的資料庫是SQLLite，所以要去&lt;a class="ext-link" href="http://sqlite.phxsoftware.com/"&gt;&lt;span class="icon"&gt;http://sqlite.phxsoftware.com/&lt;/span&gt;&lt;/a&gt;下載Sqllite的ADO.NET Driver，我下載的是SQLite-1.0.48.0-setup.exe, 執行並安裝它。&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;系統架構：&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;分成三個專案，MainConsole、Domain、Dao。MainConsole是一個Console專案，參考加入Domain、Dao。 &lt;/li&gt;&lt;li&gt;Domain是Business Entity放的地方。 &lt;/li&gt;&lt;li&gt;Dao是撈物件的介面，參考加入IBaitsNet.Common、IBaitsNet.DataMapper。 &lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Domain：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; 有三個類別，Customer繼承Party，Customer有很多Account。&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/SE3es4jLP8I/AAAAAAAAACU/Fba0E-XRtB8/s1600-h/TestORM.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/SE3es4jLP8I/AAAAAAAAACU/Fba0E-XRtB8/s320/TestORM.jpg" alt="" id="BLOGGER_PHOTO_ID_5210065206613065666" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;設定檔：&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;1. SQLMap.config這是最主要的設定檔，重點在指定資料庫的類型及連線字串，以及Map檔的位置。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;database&amp;gt;&lt;br /&gt;&amp;lt;provider name="SQLite3"/&amp;gt;&lt;br /&gt;&amp;lt;dataSource name="Test" connectionString="Data Source=Test.s3db;Version=3;useutf16encoding=false;"/&amp;gt;&lt;br /&gt;&amp;lt;/database&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;sqlMaps&amp;gt;&lt;br /&gt;&amp;lt;sqlMap resource="Maps/Customer.xml" /&amp;gt;&lt;br /&gt;&amp;lt;/sqlMaps&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;2. providers.config這是規範資料庫的連結元件，記得我是用SQLLite。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;provider name="SQLite3"&lt;br /&gt;description="SQLite, SQLite.NET provider V1.0.48.0"&lt;br /&gt;enabled="true"&lt;br /&gt;assemblyName="System.Data.SQLite, Version=1.0.48.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"&lt;br /&gt;connectionClass="System.Data.SQLite.SQLiteConnection"&lt;br /&gt;commandClass="System.Data.SQLite.SQLiteCommand"&lt;br /&gt;parameterClass="System.Data.SQLite.SQLiteParameter"&lt;br /&gt;parameterDbTypeClass="System.Data.SQLite.TypeAffinity"&lt;br /&gt;parameterDbTypeProperty="DbType"&lt;br /&gt;dataAdapterClass="System.Data.SQLite.SQLiteDataAdapter"&lt;br /&gt;commandBuilderClass="System.Data.SQLite.SQLiteCommandBuilder"&lt;br /&gt;usePositionalParameters="false"&lt;br /&gt;useParameterPrefixInSql="true"&lt;br /&gt;useParameterPrefixInParameter="true"&lt;br /&gt;parameterPrefix="@"&lt;br /&gt;setDbParameterPrecision="false"&lt;br /&gt;setDbParameterScale="false"&lt;br /&gt;allowMARS="false"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;3. Maps下放的是Mapping檔。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;alias&amp;gt;&lt;br /&gt;   &amp;lt;typeAlias alias ="Party" type ="Domain.Party,Domain"/&amp;gt;&lt;br /&gt;   &amp;lt;typeAlias alias ="Customer" type ="Domain.Customer,Domain" /&amp;gt;&lt;br /&gt;   &amp;lt;typeAlias alias ="Account" type ="Domain.Account,Domain" /&amp;gt;&lt;br /&gt;&amp;lt;/alias&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;resultMaps&amp;gt;&lt;br /&gt;   &amp;lt;resultMap id="PartyResult" class ="Party"&amp;gt;&lt;br /&gt;     &amp;lt;result property ="PartyNo" column ="PartyNo"/&amp;gt;&lt;br /&gt;     &amp;lt;result property ="Name" column ="Name" dbType="VarChar" type ="string"/&amp;gt;&lt;br /&gt;     &amp;lt;result property ="Tel" column ="Tel"/&amp;gt;&lt;br /&gt;     &amp;lt;result property ="Address" column ="Address"/&amp;gt;&lt;br /&gt;     &amp;lt;result property ="BirthDay" column ="BirthDay"/&amp;gt;&lt;br /&gt;   &amp;lt;/resultMap&amp;gt;&lt;br /&gt;   &amp;lt;resultMap id="CustomerResult" class="Customer" extends ="PartyResult"&amp;gt;&lt;br /&gt;     &amp;lt;result property="CustomerID" column="CustomerID"/&amp;gt;&lt;br /&gt;     &amp;lt;result property="AttendDate" column="AttendDate"/&amp;gt;&lt;br /&gt;     &amp;lt;result property ="CustAccount" column ="CustomerID" select ="GetAccountByCustomer"/&amp;gt;&lt;br /&gt;   &amp;lt;/resultMap&amp;gt;&lt;br /&gt;   &amp;lt;resultMap id="AccountResult" class ="Account"&amp;gt;&lt;br /&gt;     &amp;lt;result property ="AccountID" column ="AccountID"/&amp;gt;&lt;br /&gt;     &amp;lt;result property ="Level" column ="Level"/&amp;gt;&lt;br /&gt;   &amp;lt;/resultMap&amp;gt;&lt;br /&gt; &amp;lt;/resultMaps&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;statements&amp;gt;&lt;br /&gt;   &amp;lt;select id="GetCustomerByID" parameterClass="string" resultMap="CustomerResult"&amp;gt;&lt;br /&gt;     select * from Customer A,Party B&lt;br /&gt;     where A.PartyNo = B.PartyNo And CustomerID = #value#&lt;br /&gt;   &amp;lt;/select&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;select id="GetAccountByCustomer" parameterClass ="string" resultMap ="AccountResult"&amp;gt;&lt;br /&gt;     select * from Account where CustomerID = #value#&lt;br /&gt;   &amp;lt;/select&amp;gt;&lt;br /&gt; &amp;lt;/statements&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;程式：&lt;br /&gt;&lt;/span&gt; 請見CustomerDao.cs。如果設定檔名是SqlMap.config，就不必另外寫程式讀入設定檔。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;public Customer GetCustomerByID(int partyNo)&lt;br /&gt;{&lt;br /&gt;return Mapper.Instance().QueryForObject&lt;customer&gt;("GetCustomerByNo", partyNo);  &lt;br /&gt;}&lt;br /&gt;&lt;/customer&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-5766411422106698738?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/5766411422106698738/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=5766411422106698738' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/5766411422106698738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/5766411422106698738'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/06/ibaitsnetorm.html' title='IBatis.NET在ORM的簡單應用'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cvihUH5Nlq8/SE3es4jLP8I/AAAAAAAAACU/Fba0E-XRtB8/s72-c/TestORM.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-2716267144640484113</id><published>2008-06-04T20:08:00.000-07:00</published><updated>2008-06-04T20:27:56.743-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>Unity在IOC上的簡單應用</title><content type='html'>&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;關於Unity：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; Unity是微軟的新作，不知微軟哪根筋想通了，也來搞IOC。我還沒有深入研究，感覺就是很單純的IOC。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;範例：&lt;br /&gt;&lt;/span&gt; 請去&lt;a class="ext-link" href="http://www.codeplex.com/unity"&gt;&lt;span class="icon"&gt;http://www.codeplex.com/unity&lt;/span&gt;&lt;/a&gt;下載Unity Application Block 1.0.msi。參考是加入Microsoft.Practices.Unity。(最新版是1.1)&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;public enum Finger&lt;br /&gt;{&lt;br /&gt;scissors,&lt;br /&gt;paper,&lt;br /&gt;rock&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的介面&lt;br /&gt;public interface IFingerGuessing&lt;br /&gt;{&lt;br /&gt;Finger NextFinger();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的策略&lt;br /&gt;public interface IGuessingStrategy&lt;br /&gt;{&lt;br /&gt;Finger NextFinger();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的實作&lt;br /&gt;public class FingerGuessing : IFingerGuessing&lt;br /&gt;{&lt;br /&gt;private IGuessingStrategy _oneGuessing;&lt;br /&gt;public FingerGuessing(IGuessingStrategy oneGuessing)&lt;br /&gt;{&lt;br /&gt;   _oneGuessing = oneGuessing;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Finger NextFinger()&lt;br /&gt;{&lt;br /&gt;   return _oneGuessing.NextFinger();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//策略的實作&lt;br /&gt;public class FirstStrategy : IGuessingStrategy&lt;br /&gt;{&lt;br /&gt;private Finger _myFinger;&lt;br /&gt;public FirstStrategy(string myFinger)&lt;br /&gt;{&lt;br /&gt;    _myFinger = (Finger)Enum.Parse(typeof(Finger),myFinger);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Finger NextFinger()&lt;br /&gt;{&lt;br /&gt;    return _myFinger;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; 同一個啦。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;  //建立容器&lt;br /&gt;  IUnityContainer myContainer = new UnityContainer();&lt;br /&gt;&lt;br /&gt;  //這個叫動態設定，就是設定FirstStrategy的建構式要傳入rock&lt;br /&gt;  myContainer.Configure&lt;injectedmembers&gt;()&lt;br /&gt;     .ConfigureInjectionFor&lt;firststrategy&gt;(&lt;br /&gt;      new InjectionConstructor("rock")&lt;br /&gt;    );&lt;br /&gt;&lt;br /&gt;  //加入组件&lt;br /&gt;  myContainer.RegisterType&lt;iguessingstrategy, firststrategy=""&gt;();&lt;br /&gt;  myContainer.RegisterType&lt;ifingerguessing, fingerguessing=""&gt;();&lt;br /&gt;&lt;br /&gt;  //取得组件&lt;br /&gt;  IFingerGuessing startGame = myContainer.Resolve&lt;ifingerguessing&gt;();&lt;br /&gt;&lt;br /&gt;  //使用组件&lt;br /&gt;  Console.Write(startGame.NextFinger().ToString());&lt;br /&gt;&lt;br /&gt;  Console.ReadLine();&lt;br /&gt;}&lt;br /&gt;&lt;/ifingerguessing&gt;&lt;/ifingerguessing,&gt;&lt;/iguessingstrategy,&gt;&lt;/firststrategy&gt;&lt;/injectedmembers&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;設定檔：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; 沒有，因為我們用了動態設定。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-2716267144640484113?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/2716267144640484113/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=2716267144640484113' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/2716267144640484113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/2716267144640484113'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/06/unityioc.html' title='Unity在IOC上的簡單應用'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-4422596598458365574</id><published>2008-06-02T19:05:00.000-07:00</published><updated>2008-07-21T22:43:16.587-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>NHibernate在ORM上的簡單應用</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言：&lt;br /&gt;&lt;/span&gt;nHibernate是Hibernate的.NET版。Hibernate我接觸不多，能理解的，就是先設計好物件，才產生資料庫。為了實現各種物件的 關係，建立起無SQL的環境，hibernate真的是煞費苦心，考量了種種情形。所以也只有能設計出純OO系統的人，能享受它的各種便利。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;系統環境：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;請去&lt;a class="ext-link" href="http://www.hibernate.org/343.html"&gt;&lt;span class="icon"&gt;http://www.hibernate.org/343.html&lt;/span&gt;&lt;/a&gt;下載最新版，我下載的是NHibernate-1.2.1.GA.msi。 &lt;/li&gt;&lt;li&gt;資料庫是用SQLLite，請去&lt;a class="ext-link" href="http://sqlite.phxsoftware.com/"&gt;&lt;span class="icon"&gt;http://sqlite.phxsoftware.com/&lt;/span&gt;&lt;/a&gt;，下載最新版。&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;系統架構：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;Dao就是撈取物件的介面，參考加入NHibernate.dll。 &lt;/li&gt;&lt;li&gt;Domain是Business Entity的擺放位置。 &lt;/li&gt;&lt;li&gt;MainConsole代表這是一個Console程式，參考加入Dao、Domain。這邊要注意的是雖然System.Data.SQLite.DLL註冊到GAC去了，但nH還是找不到的，需要複製一份在執行目錄下。 &lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Domain：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SESnrUMZQLI/AAAAAAAAACM/mXUX6HMpzSY/s1600-h/TestORM.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SESnrUMZQLI/AAAAAAAAACM/mXUX6HMpzSY/s320/TestORM.jpg" alt="" id="BLOGGER_PHOTO_ID_5207471431744045234" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;有三個類別，Customer繼承Party，Customer有很多Account。&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;設定檔：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; 設定檔要注意的細節很多。 App.Config要注意，我是用System.Data.SQLLite.dll跟官方的不同，所以要在DbProviderFactory註明。hibernate.connection.driver_class也要注意是NHibernate.Driver.SQLite20Driver喔。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;configsections&amp;gt;&lt;br /&gt;&amp;lt;section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"&amp;gt;&lt;br /&gt;&amp;lt;/section&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;system.data&amp;gt;&lt;br /&gt;&amp;lt;dbproviderfactories&amp;gt;&lt;br /&gt;&amp;lt;remove invariant="System.Data.SQLite"&amp;gt;&lt;br /&gt;&amp;lt;add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite"&amp;gt;&lt;br /&gt;&amp;lt;/DbProviderFactories&amp;gt;&lt;br /&gt;&amp;lt;/system.data&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;nhibernate&amp;gt;&lt;br /&gt;&amp;lt;add key="hibernate.show_sql" value="false"/&amp;gt;&lt;br /&gt;&amp;lt;add key="hibernate.dialect" value="NHibernate.Dialect.SQLiteDialect"/&amp;gt;&lt;br /&gt;&amp;lt;add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/&amp;gt;&lt;br /&gt;&amp;lt;add key="hibernate.connection.driver_class" value="NHibernate.Driver.SQLite20Driver"/&amp;gt;&lt;br /&gt;&amp;lt;add key="hibernate.connection.connection_string" value="Data Source=Test.s3db;Version=3"/&amp;gt;&lt;br /&gt;&amp;lt;add key="hibernate.query.substitutions" value="true=1;false=0"/&amp;gt;&lt;br /&gt;&amp;lt;/nhibernate&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Customer.hbm.xml：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; 我的繼承策略，hibernate叫table per subclass。子類別還有一個集合，所以寫來像這樣。它是一個內嵌資源喔。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Domain" assembly="Domain"&amp;gt;&lt;br /&gt;&amp;lt;class name="Party" table="Party"&amp;gt;&lt;br /&gt;&amp;lt;id name="PartyNo" column="PartyNo" type="int"&amp;gt;&lt;br /&gt;&amp;lt;generator class="assigned" /&amp;gt;&lt;br /&gt;&amp;lt;/id&amp;gt;&lt;br /&gt;&amp;lt;property name="Name" type="String" /&amp;gt;&lt;br /&gt;&amp;lt;property name="Tel" type="String" /&amp;gt;&lt;br /&gt;&amp;lt;property name="Address" type="String" /&amp;gt;&lt;br /&gt;&amp;lt;property name="BirthDay" type="Date" /&amp;gt;&lt;br /&gt;&amp;lt;joined-subclass name="Customer" table="Customer"&amp;gt;&lt;br /&gt;&amp;lt;key column="PartyNo"/&amp;gt;&lt;br /&gt;&amp;lt;property name="CustomerID" type="String" /&amp;gt;&lt;br /&gt;&amp;lt;property name="AttendDate" type="Date" /&amp;gt;&lt;br /&gt;&amp;lt;list name="CustAccount"&amp;gt;&lt;br /&gt;  &amp;lt;key column="customerID"/&amp;gt;&lt;br /&gt;  &amp;lt;index column="SortNo"&amp;gt;&amp;lt;/index&amp;gt;&lt;br /&gt;  &amp;lt;one-to-many class="Account"/&amp;gt;&lt;br /&gt;&amp;lt;/list&amp;gt;&lt;br /&gt;&amp;lt;/joined-subclass&amp;gt;&lt;br /&gt;&amp;lt;/class&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;class name="Account" table="Account"&amp;gt;&lt;br /&gt;&amp;lt;id type="String" column="AccountID" name="AccountID"&amp;gt;&lt;br /&gt;&amp;lt;generator class="assigned" /&amp;gt;&lt;br /&gt;&amp;lt;/id&amp;gt;&lt;br /&gt;&amp;lt;property type="int" column="Level" name="Level"/&amp;gt;&lt;br /&gt;&amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;程式：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; 第一個要注意的，要匯入設定檔，需要一個Singleton的ISessionFactory物件，寫在Sessions.cs&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;public class Sessions&lt;br /&gt;{&lt;br /&gt;private static readonly object lockObj = new object();&lt;br /&gt;private static ISessionFactory _factory;&lt;br /&gt;&lt;br /&gt;public Sessions(){}&lt;br /&gt;&lt;br /&gt;public static ISessionFactory Factory&lt;br /&gt;{&lt;br /&gt;   get&lt;br /&gt;   {&lt;br /&gt;       if (_factory == null)&lt;br /&gt;       {&lt;br /&gt;           lock (lockObj)&lt;br /&gt;           {&lt;br /&gt;               if (_factory == null)&lt;br /&gt;               {&lt;br /&gt;                    NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration()&lt;br /&gt;                   .AddAssembly("MainConsole");&lt;br /&gt;                   _factory = cfg.BuildSessionFactory();&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;       }&lt;br /&gt;       return _factory;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;public static ISession GetSession()&lt;br /&gt;{&lt;br /&gt;   return Factory.OpenSession();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;public class CustomerDao&lt;br /&gt;{&lt;br /&gt; public Party GetCustomerByNo(int partyNo)&lt;br /&gt; {&lt;br /&gt;     ISession handler = null;&lt;br /&gt;&lt;br /&gt;     try&lt;br /&gt;     {&lt;br /&gt;         handler = Sessions.GetSession();&lt;br /&gt;         return handler.Get&lt;party&gt;(partyNo);&lt;br /&gt;     }&lt;br /&gt;     catch (Exception ex)&lt;br /&gt;     {&lt;br /&gt;         throw;&lt;br /&gt;     }&lt;br /&gt;     finally&lt;br /&gt;     {&lt;br /&gt;         handler.Close();&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/party&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-4422596598458365574?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/4422596598458365574/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=4422596598458365574' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4422596598458365574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4422596598458365574'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/06/nhibernateorm.html' title='NHibernate在ORM上的簡單應用'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/SESnrUMZQLI/AAAAAAAAACM/mXUX6HMpzSY/s72-c/TestORM.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-7217910999078496896</id><published>2008-06-01T18:27:00.000-07:00</published><updated>2008-07-22T20:05:47.058-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>Spring.NET在IOC的簡單應用</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言：&lt;br /&gt;&lt;/span&gt;IOC的觀念，請參考網路上的文章。這裏僅介紹Spring.NET的IOC用法。Spring.NET的特色，就是跟Java的血統一樣，就是要寫很多 的設定檔。它對nHibernate有很好的支援，Web端有個自己的framework，是一個很完整的中間層framework。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; 請去&lt;a class="ext-link" href="http://www.springframework.net/"&gt;&lt;span class="icon"&gt;http://www.springframework.net/&lt;/span&gt;&lt;/a&gt;下載最新版Spring.NET-1.1.2.exe。然後初步研究參考要加入這三個，Common.Logging、Common.Logging.Log4Net、Spring.Core;&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public enum Finger&lt;br /&gt;{&lt;br /&gt; scissors,&lt;br /&gt; paper,&lt;br /&gt; rock&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的介面&lt;br /&gt;public interface IFingerGuessing&lt;br /&gt;{&lt;br /&gt; Finger NextFinger();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的策略&lt;br /&gt;public interface IGuessingStrategy&lt;br /&gt;{&lt;br /&gt; Finger NextFinger();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的實作&lt;br /&gt;public class FingerGuessing : IFingerGuessing&lt;br /&gt;{&lt;br /&gt; private IGuessingStrategy _oneGuessing;&lt;br /&gt; public FingerGuessing(IGuessingStrategy oneGuessing)&lt;br /&gt; {&lt;br /&gt;     _oneGuessing = oneGuessing;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Finger NextFinger()&lt;br /&gt; {&lt;br /&gt;     return _oneGuessing.NextFinger();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//策略的實作&lt;br /&gt;public class FirstStrategy : IGuessingStrategy&lt;br /&gt;{&lt;br /&gt; private Finger _myFinger;&lt;br /&gt; public FirstStrategy(string myFinger)&lt;br /&gt; {&lt;br /&gt;     _myFinger = (Finger)Enum.Parse(typeof(Finger),myFinger);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Finger NextFinger()&lt;br /&gt; {&lt;br /&gt;     return _myFinger;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這是用同一個範例，用Spring.NET的寫法像這樣&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt; //建立容器&lt;br /&gt; IApplicationContext ctx = ContextRegistry.GetContext();&lt;br /&gt; IFingerGuessing startGame = (IFingerGuessing)ctx.GetObject("GuessingGame");&lt;br /&gt;&lt;br /&gt; //使用组件&lt;br /&gt; Console.Write(startGame.NextFinger().ToString());&lt;br /&gt;&lt;br /&gt; Console.ReadLine();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;之所以語法那麼乾淨，是因為所有的細節都寫在設定檔了。&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;設定檔：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;lt;configSections&amp;gt;&lt;br /&gt;  &amp;lt;sectionGroup name="spring"&amp;gt;&lt;br /&gt;    &amp;lt;section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/&amp;gt;&lt;br /&gt;    &amp;lt;section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" /&amp;gt;&lt;br /&gt;  &amp;lt;/sectionGroup&amp;gt;&lt;br /&gt;  &amp;lt;!-- 因為有使用Log4Net吧，所以多出這兩個--&amp;gt;&lt;br /&gt;  &amp;lt;sectionGroup name="common"&amp;gt;&lt;br /&gt;    &amp;lt;section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /&amp;gt;&lt;br /&gt;  &amp;lt;/sectionGroup&amp;gt;&lt;br /&gt;  &amp;lt;section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /&amp;gt;&lt;br /&gt;&amp;lt;/configSections&amp;gt;&lt;br /&gt;&amp;lt;common&amp;gt;&lt;br /&gt;  &amp;lt;logging&amp;gt;&lt;br /&gt;    &amp;lt;factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net"&amp;gt;&lt;br /&gt;      &amp;lt;arg key="configType" value="INLINE" /&amp;gt;&lt;br /&gt;    &amp;lt;/factoryAdapter&amp;gt;&lt;br /&gt;  &amp;lt;/logging&amp;gt;&lt;br /&gt;&amp;lt;/common&amp;gt;&lt;br /&gt;&amp;lt;spring&amp;gt;&lt;br /&gt;  &amp;lt;context&amp;gt;&lt;br /&gt;    &amp;lt;!-- 表示設定寫在同一設定檔--&amp;gt;&lt;br /&gt;    &amp;lt;resource uri="config://spring/objects"/&amp;gt;&lt;br /&gt;  &amp;lt;/context&amp;gt;&lt;br /&gt;  &amp;lt;objects xmlns="http://www.springframework.net"&amp;gt;&lt;br /&gt;    &amp;lt;object name="MyStrategy" type="ConsoleTest.FirstStrategy,ConsoleTest"&amp;gt;&lt;br /&gt;      &amp;lt;constructor-arg name="myFinger" value="rock"/&amp;gt;&lt;br /&gt;    &amp;lt;/object&amp;gt;&lt;br /&gt;    &amp;lt;object name="GuessingGame" type="ConsoleTest.FingerGuessing, ConsoleTest"&amp;gt;&lt;br /&gt;      &amp;lt;constructor-arg index ="0" ref="MyStrategy"/&amp;gt;&lt;br /&gt;    &amp;lt;/object&amp;gt;&lt;br /&gt;  &amp;lt;/objects&amp;gt;&lt;br /&gt;&amp;lt;/spring&amp;gt;&lt;br /&gt;&amp;lt;log4net&amp;gt;&lt;br /&gt;  &amp;lt;!-- 這裏是Log4Net的設定--&amp;gt;&lt;br /&gt;  &amp;lt;appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"&amp;gt;&lt;br /&gt;    &amp;lt;layout type="log4net.Layout.PatternLayout"&amp;gt;&lt;br /&gt;      &amp;lt;conversionPattern value="%date [%thread] %-5level %logger - %message%newline" /&amp;gt;&lt;br /&gt;    &amp;lt;/layout&amp;gt;&lt;br /&gt;  &amp;lt;/appender&amp;gt;&lt;br /&gt;  &amp;lt;root&amp;gt;&lt;br /&gt;    &amp;lt;level value="DEBUG" /&amp;gt;&lt;br /&gt;    &amp;lt;appender-ref ref="ConsoleAppender" /&amp;gt;&lt;br /&gt;  &amp;lt;/root&amp;gt;&lt;br /&gt;  &amp;lt;logger name="Spring"&amp;gt;&lt;br /&gt;    &amp;lt;level value="INFO" /&amp;gt;&lt;br /&gt;  &amp;lt;/logger&amp;gt;&lt;br /&gt;&amp;lt;/log4net&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-7217910999078496896?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/7217910999078496896/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=7217910999078496896' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/7217910999078496896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/7217910999078496896'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/06/springnetioc.html' title='Spring.NET在IOC的簡單應用'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-5964032002026440538</id><published>2008-05-30T01:21:00.000-07:00</published><updated>2008-05-30T01:44:28.854-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>IOC在Windsor的簡單應用</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言：&lt;br /&gt;&lt;/span&gt;在OO設計時，為了讓物件可以低耦的狀態，通常都會設計出介面，讓兩個物件不直接關聯，而是都關聯介面，這是OO的依賴反轉。然後為了讓物件可以高聚，我 們也會把一個物件打散成一堆小物件，增加重用性。當我們要使用某個功能時，必然是把所有的相關物件全部New起來，組合完畢後開始使用，這是OO設計的常 識。&lt;br /&gt;IOC容器的觀點，就是把New的步驟，及組合的程序從程式中抽離出來。透過設定檔設定，讓程式執行時，自動去取得相關的物件。好處是程式中沒有指定產生 任何的物件，即沒有new這個語法的出現。一切都是容器產生，程式需要該物件時，才去取用。這讓我們寫好的系統，可以在執行時期自由改變功能。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;關於Windsor：&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: normal;font-size:100%;" &gt;.NET比較有名的IOC容器有三套，Windor、Spring.NET、Unity。就對IOC的支援上，算是大同小異。SPring.NET喜歡寫 設定檔，Windosr與Unity是可寫可不寫。Windsor與Spring.NET可以整合前後端的framework，變成中間層的架構。而 Unity就只是基本的IOC容器。&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;範例：&lt;br /&gt;&lt;/span&gt; 講到這裏，還是來快速入門吧。先去&lt;a class="ext-link" href="http://www.castleproject.org/"&gt;&lt;span class="icon"&gt;http://www.castleproject.org/&lt;/span&gt;&lt;/a&gt;去取得CastleProject-1.0-RC3.msi。安裝完畢後，你的VsIDE就產生兩種專案型別，一個是Monorail，一個是ActiveRocord。先來開一個新的Console專案。有以下幾個類別：&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public enum Finger&lt;br /&gt;{&lt;br /&gt;scissors,&lt;br /&gt;paper,&lt;br /&gt;rock&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的介面&lt;br /&gt;public interface IFingerGuessing&lt;br /&gt;{&lt;br /&gt;Finger NextFinger();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的策略&lt;br /&gt;public interface IGuessingStrategy&lt;br /&gt;{&lt;br /&gt;Finger NextFinger();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//猜拳遊戲的實作&lt;br /&gt;public class FingerGuessing : IFingerGuessing&lt;br /&gt;{&lt;br /&gt;private IGuessingStrategy _oneGuessing;&lt;br /&gt;public FingerGuessing(IGuessingStrategy oneGuessing)&lt;br /&gt;{&lt;br /&gt;_oneGuessing = oneGuessing;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Finger NextFinger()&lt;br /&gt;{&lt;br /&gt; return _oneGuessing.NextFinger();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//策略的實作&lt;br /&gt;public class FirstStrategy : IGuessingStrategy&lt;br /&gt;{&lt;br /&gt;private Finger _myFinger;&lt;br /&gt;public FirstStrategy(string myFinger)&lt;br /&gt;{&lt;br /&gt;  _myFinger = (Finger)Enum.Parse(typeof(Finger),myFinger);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Finger NextFinger()&lt;br /&gt;{&lt;br /&gt;  return _myFinger;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;以上是一個經典的Strategy Pattern。如果不使用IOC的話，總是在程式的某個地方，你要各挑一個實作這兩個介面的物件，把他們結合在一起來操作。例如：&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;IGuessingStrategy oneStrategy = new FirstStrategy();&lt;br /&gt;IFingerGuessing oneGame = new FingerGuessing(oneStrategy);&lt;br /&gt;&lt;br /&gt;Finger nextFinger = oneGame.NextFinger();&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;只要策略代入別的，下一拳就會不同，這是很好的責任分配。那用IOC又如何呢?&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;//建立容器&lt;br /&gt;IWindsorContainer container =&lt;br /&gt;   new WindsorContainer(&lt;br /&gt;       new XmlInterpreter(&lt;br /&gt;           new ConfigResource("castle")));&lt;br /&gt;&lt;br /&gt;//加入组件&lt;br /&gt;container.AddComponent("GuessingGame", typeof(IFingerGuessing), typeof(FingerGuessing));&lt;br /&gt;container.AddComponent("MyStrategy", typeof(IGuessingStrategy), typeof(FirstStrategy));&lt;br /&gt;&lt;br /&gt;//取得组件，這個物件因為在建構式上有指定傳入IGuessingStrategy的介面，所以就自動合在一起了&lt;br /&gt; IFingerGuessing startGame = (IFingerGuessing)container["GuessingGame"];&lt;br /&gt;&lt;br /&gt;////使用组件&lt;br /&gt; Console.Write(startGame.NextFinger().ToString());&lt;br /&gt;&lt;br /&gt; Console.ReadLine();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;設定檔：&lt;/span&gt;&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;lt;configsections&amp;gt;&lt;br /&gt; &amp;lt;section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"&amp;gt;&lt;br /&gt;&amp;lt;/section&amp;gt;&lt;br /&gt;&amp;lt;castle&amp;gt;&lt;br /&gt; &amp;lt;components&amp;gt;&lt;br /&gt;   &amp;lt;component id="MyStrategy"&amp;gt;&lt;br /&gt;     &amp;lt;parameters&amp;gt;&lt;br /&gt;       &amp;lt;!--策略物件有個要傳進來的值吧，這裏可以設定傳進來--&amp;gt;&lt;br /&gt;       &amp;lt;myfinger&amp;gt;rock&amp;lt;/myfinger&amp;gt;&lt;br /&gt;     &amp;lt;/parameters&amp;gt;&lt;br /&gt;   &amp;lt;/component&amp;gt;&lt;br /&gt; &amp;lt;/components&amp;gt;&lt;br /&gt;&amp;lt;/castle&amp;gt;&lt;br /&gt;&amp;lt;/configsections&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-5964032002026440538?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/5964032002026440538/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=5964032002026440538' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/5964032002026440538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/5964032002026440538'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/05/iocwindsor.html' title='IOC在Windsor的簡單應用'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3401797331709561594</id><published>2008-05-07T02:04:00.000-07:00</published><updated>2008-05-07T02:24:16.762-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開發流程'/><title type='text'>ICONIX--敏捷方法論</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言： &lt;/span&gt;&lt;br /&gt;ICONIX方法論，簡化了RUP的繁頊，卻仍保有RUP那種穩健推論的特質。我對RUP的認識不深，直覺的想法，這是一個重量級的開發流程。這表示它有大量的文件，精細的人員配置。RUP使用了Use Case來做為最初的系統需求，曾經讓我摸不著頭緒。文字有時是一種釐清思緒的工具，卻不是一種有創造力的工具。文字的表達也不夠直接，容易有模糊的空間。再者Use Case不但經常語意不清，而且還有難以規範的精確程度，很多人把畫面上的細微操作也當成Use Case在寫。產生大量的Use Case後，不但難以維護，其實與真正要產生的設計也有一大段距離。最糟糕的是，耗盡心力寫出來的Use Case，很多人會將它當成合同的一部分，死也不想去改。以上僅代表個人不成熟意見。ICONIX亦使用Use Case，但是是一種搭配著Robustness Diagram使用，到達一種剛好使所有人明白的程度。&lt;br /&gt;&lt;br /&gt;ICONIX當然也是一種迭代式的開發，每次開發順著分析-&gt;設計-&gt;Coding-&gt;Test前進，一次比一次更接近使用者的需求。它的開發腳步也是建議我們自訂，當你感覺分析的程度夠了，就會進入設計，設計的程度夠了，就能開始Coding。所謂的時候到了，代表著所有的圖形到達一種完整銜接、反覆推理皆合理的狀態。&lt;br /&gt;&lt;h3 id="RobustnessDiagram"&gt;&lt;span style="font-size:100%;"&gt;Robustness Diagram：&lt;/span&gt;&lt;/h3&gt;ICONIX最大的特色在於Robustness Diagram的使用，補足Use Case與Sequence Diagram的代溝。使得ProtoType -&gt; Use Case -&gt;Robustness Diagram -&gt;Sequence Diagram，變成一組故事系統，互相支援。而Sequence Diagram完成後，進入設計的階段將更為容易。Domain Model仍有一席之地，但是是為了來補捉系統所有會出現的概念或名詞，像是一個領域字典。Use Case在有了User初步認可的ProtoType及Domain Model後，就可開始撰寫。一邊撰寫，一邊用Robustness Diagram來補助，凡先前做出的所有畫面及名詞，Robustness Diagram皆該一一補捉。這樣子就可以推理出非常合乎真實需求的分析。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SCFzxok_R2I/AAAAAAAAACE/S89rBP85yqk/s1600-h/ICONIX.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SCFzxok_R2I/AAAAAAAAACE/S89rBP85yqk/s320/ICONIX.png" alt="" id="BLOGGER_PHOTO_ID_5197562741505607522" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3 id="開發流程"&gt;&lt;span style="font-size:100%;"&gt;開發流程：&lt;/span&gt;&lt;/h3&gt; 正如我之前說的，ICONIX對於每個必須產出什麼，沒有那麼嚴苛的規定，你覺得程度到了，也就是該進入下一流程。&lt;br /&gt;&lt;h4 id="RequirementsAnalysis"&gt;&lt;span style="font-size:85%;"&gt;Requirements Analysis：&lt;/span&gt;&lt;/h4&gt; &lt;ol&gt;&lt;li&gt;開始畫Domain Model。這是為了確認領域內會出現的概念或名詞，不必有方法屬性 。 &lt;/li&gt;&lt;li&gt;製作ProtoType，免不了的過程。 &lt;/li&gt;&lt;li&gt;畫Use Case Diagram，我覺得這個部分很像是FDD的Feature Set，找出所有的功能。 &lt;/li&gt;&lt;li&gt;歸類Use Case，這也很像是FDD的Subject Area，歸類功能的群組。 &lt;/li&gt;&lt;li&gt;確認所有的需求，都在Domain Model及Use Case中。 &lt;/li&gt;&lt;/ol&gt;&lt;h4 id="AnalysisandPreliminaryDesign"&gt;&lt;span style="font-size:85%;"&gt;Analysis and Preliminary Design： &lt;/span&gt;&lt;/h4&gt; &lt;ol&gt;&lt;li&gt;開始寫Use Case中的流程，主線劇情、分支劇情、錯誤分支。 &lt;/li&gt;&lt;li&gt;開始畫Robustness Diagram。有了畫面、劇情、還有必要的概念。Robustness Diagram幫助我們找出更多Domain Object、檢驗Use Case的合理性。 &lt;/li&gt;&lt;li&gt;畫出Class Diagram，畫完Robustness Diagram，我們可以知道有多少Domain Object及控制類、這會產生初步的類別圖。確認這個類別圖滿足所有的系統需求。 &lt;/li&gt;&lt;/ol&gt;&lt;h4 id="Design"&gt;&lt;span style="font-size:85%;"&gt;Design： &lt;/span&gt;&lt;/h4&gt; &lt;ol&gt;&lt;li&gt;畫出Sequence Diagram，使用剛才的類別圖，以及Robustness Diagram，就可以畫出來了。 &lt;/li&gt;&lt;li&gt;把之前的類別圖更進一步推衍，例如為了重用，使用不同的Design Pattern。 &lt;/li&gt;&lt;li&gt;確認所有的設計都滿足了系統需求。 &lt;/li&gt;&lt;/ol&gt;&lt;h4 id="Implementation"&gt;&lt;span style="font-size:85%;"&gt;Implementation：&lt;/span&gt;&lt;/h4&gt; &lt;ol&gt;&lt;li&gt;如必要，配置圖。 &lt;/li&gt;&lt;li&gt;寫Code。 &lt;/li&gt;&lt;li&gt;單元測試及整合測試。 &lt;/li&gt;&lt;li&gt;可行性測試，最終的使用者測試。 &lt;/li&gt;&lt;/ol&gt;&lt;h3 id="參考資料"&gt;&lt;span style="font-size:100%;"&gt;參考資料：&lt;/span&gt;&lt;/h3&gt;Applying Use Case Driven Object Modeling with UML: An Annotated e-Commerce Example ：Doug Rosenberg Kendall Scott Publisher: Addison Wesley：嗯，就像FDD之於Java Modeling With UML In Color的書。&lt;br /&gt;&lt;a class="ext-link" href="http://www.iconixsw.com/"&gt;&lt;span class="icon"&gt;http://www.iconixsw.com/&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3401797331709561594?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3401797331709561594/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3401797331709561594' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3401797331709561594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3401797331709561594'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/05/iconix.html' title='ICONIX--敏捷方法論'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/SCFzxok_R2I/AAAAAAAAACE/S89rBP85yqk/s72-c/ICONIX.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-4852583047462148959</id><published>2008-05-02T00:13:00.000-07:00</published><updated>2008-05-02T02:41:08.915-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='工具'/><title type='text'>PartCover的使用介紹</title><content type='html'>&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;前言&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;NCover要收錢後，當然整個Open Source界就是一整個不爽，就有人加緊生出替代品了，這叫PartCover，已經被SharpDevelop所採用。可能有人不懂這兩套是做什麼 的，做的是Code Coverage的工作，就是計算程式碼中被測試程式執行過的比例。100%當然不代表沒有Bug，但總是一個輔助的工具。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;使用方法&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;  &lt;/span&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:130%;"&gt;準備好你的專案，並為它加上測試程式，這裏限用NUnit。&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre style="background-color: lightgrey; color: green;"&gt;&lt;code&gt;public class Employee&lt;br /&gt;{&lt;br /&gt;public int CalSalary(int seniority, int career)&lt;br /&gt;{&lt;br /&gt;int salary = 18000;&lt;br /&gt;double salaryPower;&lt;br /&gt;&lt;br /&gt;switch (seniority)&lt;br /&gt;{&lt;br /&gt;case 0:&lt;br /&gt;salaryPower = 1.0;&lt;br /&gt;break;&lt;br /&gt;case 1:&lt;br /&gt;salaryPower = 1.1;&lt;br /&gt;break;&lt;br /&gt;case 2:&lt;br /&gt;salaryPower = 1.2;&lt;br /&gt;break;&lt;br /&gt;case 3:&lt;br /&gt;salaryPower = 1.4;&lt;br /&gt;break;&lt;br /&gt;case 4:&lt;br /&gt;salaryPower = 1.5;&lt;br /&gt;break;&lt;br /&gt;default:&lt;br /&gt;salaryPower = 1.6;&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;switch (career)&lt;br /&gt;{&lt;br /&gt;case 1:&lt;br /&gt;salary = 18000;&lt;br /&gt;break;&lt;br /&gt;case 2:&lt;br /&gt;salary = 23000;&lt;br /&gt;break;&lt;br /&gt;case 3:&lt;br /&gt;salary = 28000;&lt;br /&gt;break;&lt;br /&gt;case 4:&lt;br /&gt;salary = 33000;&lt;br /&gt;break;&lt;br /&gt;case 5:&lt;br /&gt;salary = 38000;&lt;br /&gt;break;&lt;br /&gt;default:&lt;br /&gt;salary = 40000;&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return (int)Math.Round(salary * salaryPower);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style="background-color: lightgrey; color: green;"&gt;&lt;code&gt;[TestFixture]&lt;br /&gt;public class TestEmployee&lt;br /&gt;{&lt;br /&gt;private Employee _me;&lt;br /&gt;&lt;br /&gt;[SetUp]&lt;br /&gt;public void SetUp()&lt;br /&gt;{&lt;br /&gt;_me = new Employee();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestCalSalary()&lt;br /&gt;{&lt;br /&gt;Assert.AreEqual(19800, _me.CalSalary(1, 1));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; 看才算出一種身份薪水，其他部分都沒測，我們用PartCover來證明工程師偷懶了。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;使用PartCover可以用Console模式，也可以用Gui模式。打開PartCover Converage Browser。&lt;/li&gt;&lt;/ul&gt;&lt;ol class="upperroman"&gt;&lt;li&gt;Code Converage一定要搭配一組單元測試的framework，所以Execute File選nunit-console.exe。 &lt;/li&gt;&lt;li&gt;Working Directory一定要指回PartCover的目錄，它要回去抓xslt檔。 &lt;/li&gt;&lt;li&gt;Working Arguments這個其實是Nunit的參數，選擇你要測試的編譯檔。 &lt;/li&gt;&lt;li&gt;Rules是指要載入的dll名字及類別的名字，+是表示加進來，-是表示排除。所以&lt;/li&gt;&lt;/ol&gt;&lt;pre style="background-color: lightgrey; color: green;"&gt;&lt;code&gt; +[!MainProject]* = !MainProject這個專案下的所有專案&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SBrBVM5YrkI/AAAAAAAAABM/uX93k5hdl1E/s1600-h/PartCover.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SBrBVM5YrkI/AAAAAAAAABM/uX93k5hdl1E/s320/PartCover.jpg" alt="" id="BLOGGER_PHOTO_ID_5195677690108620354" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;跑吧，原來PartCover認為Employee裏面CalSalary只有測試到51%，真是不及格呢。&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBrBrc5YrlI/AAAAAAAAABU/YtY8L7QCN5M/s1600-h/PartCover1.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBrBrc5YrlI/AAAAAAAAABU/YtY8L7QCN5M/s320/PartCover1.jpg" alt="" id="BLOGGER_PHOTO_ID_5195678072360709714" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-4852583047462148959?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/4852583047462148959/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=4852583047462148959' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4852583047462148959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4852583047462148959'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/05/partcover.html' title='PartCover的使用介紹'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/SBrBVM5YrkI/AAAAAAAAABM/uX93k5hdl1E/s72-c/PartCover.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-8340760445649697354</id><published>2008-04-24T06:46:00.001-07:00</published><updated>2008-05-02T02:40:39.656-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>MVP Pattern在ASP.NET上的應用(2)</title><content type='html'>承繼上篇，繼續來講3、4、5&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;方法3：&lt;br /&gt;&lt;/span&gt; 方法3的想法是這樣的，以下寫法也是對的，只是每個Presentery都要加這兩句，未免浪費：&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public SecondPresenter(ISecondView currentView)&lt;br /&gt;{&lt;br /&gt;_currentView = currentView;&lt;br /&gt;_currentView.AttachPresenter(this);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; 建立一個IViewBase，讓所有的IView都實作它。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public interface IViewBase&lt;br /&gt;{&lt;br /&gt;void AttachPresenter(IPresenterBase presenter);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; 建立一個PresenterBase&lt;t&gt;的泛型，把這兩行填進來，以後繼承的就不必再填這兩行。&lt;/t&gt;&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public class PresenterBase&lt;t&gt;  : IPresenterBase where T : IViewBase&lt;br /&gt;{&lt;br /&gt;protected readonly T _currentView;&lt;br /&gt;&lt;br /&gt;public PresenterBase(T currentView)&lt;br /&gt;{&lt;br /&gt;_currentView = currentView;&lt;br /&gt;_currentView.AttachPresenter(this);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/t&gt;&lt;/code&gt;&lt;/pre&gt; ThirdPresenter.cs如下：&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public class ThirdPresenter : PresenterBase&lt;ithirdview&gt;&lt;br /&gt;{&lt;br /&gt;public ThirdPresenter(IThirdView currentView)&lt;br /&gt;: base(currentView)&lt;br /&gt;{&lt;br /&gt;//已經不需要那兩行&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void initView(bool isPostBack)&lt;br /&gt;{&lt;br /&gt;if (!isPostBack)&lt;br /&gt;{&lt;br /&gt; _currentView.CurrentDateTime = DateTime.Now;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void AddMonths(int months)&lt;br /&gt;{&lt;br /&gt;_currentView.CurrentDateTime = _currentView.CurrentDateTime.AddMonths(1);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/ithirdview&gt;&lt;/code&gt;&lt;/pre&gt; 所以ThirdView.aspx.cs也很乾淨。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt; protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;ThirdPresenter myPresenter = new ThirdPresenter(myAddMonths);&lt;br /&gt;myPresenter.initView(IsPostBack);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; View這邊也建立一個ViewBase，把多餘的Code吸收掉。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public class ViewBase&amp;lt;t&amp;gt; : System.Web.UI.UserControl,IViewBase where T : IPresenterBase&lt;br /&gt;{&lt;br /&gt;protected T _currentPresenter;&lt;br /&gt;&lt;br /&gt;public void AttachPresenter(IPresenterBase presenter)&lt;br /&gt;{&lt;br /&gt;this._currentPresenter = (T)presenter;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;方法4：&lt;br /&gt;&lt;/span&gt; 方法4的想法是這樣，目前每個View都要保持一個Presenter的參考。但如果用事件來處理，View就只管發訊息，不必知道P那邊有什麼Method。所以IFourthView.cs如下：&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;public interface IFourthView&lt;br /&gt;{&lt;br /&gt;DateTime CurrentDateTime { get;set;}&lt;br /&gt;&lt;br /&gt;//EventHandler是.NET內附的泛型事件，可以在New才指定要傳哪一類的事件參數。我們乾脆再做一個事件參數的泛型，在New時才指定要回傳的型別。&lt;br /&gt;event EventHandler&amp;lt;eventargs&amp;gt;&amp;lt;int&amp;gt;&amp;gt; YearsAdded;&lt;br /&gt;}&lt;br /&gt;//自建的泛型EventArgs&lt;br /&gt;public class EventArgs&amp;lt;t&amp;gt; : EventArgs&lt;br /&gt;{&lt;br /&gt;private T _value;&lt;br /&gt;&lt;br /&gt;public EventArgs(T value)&lt;br /&gt;{&lt;br /&gt;  _value = value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public T Value&lt;br /&gt;{&lt;br /&gt;  get { return _value; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;FourthPresenter發生什麼事呢&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;public class FourthPresenter&lt;br /&gt;{&lt;br /&gt;private IFourthView _currentView;&lt;br /&gt;&lt;br /&gt;public FourthPresenter(IFourthView currentView)&lt;br /&gt;{&lt;br /&gt;   this._currentView = currentView;&lt;br /&gt;&lt;br /&gt;   //由Presenter接收事件&lt;br /&gt;   _currentView.YearsAdded += new EventHandler&amp;lt;eventargs&amp;gt;&amp;lt;int&amp;gt;&amp;gt;(_currentView_YearsAdded);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void initView(bool isPostBack)&lt;br /&gt;{&lt;br /&gt;   if (!isPostBack)&lt;br /&gt;   {&lt;br /&gt;       _currentView.CurrentDateTime = DateTime.Now;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;private void _currentView_YearsAdded(object sender, EventArgs&amp;lt;int&amp;gt; e)&lt;br /&gt;{&lt;br /&gt;   _currentView.CurrentDateTime = _currentView.CurrentDateTime.AddYears(e.Value);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;AddYears現在只要發出事件就好，不必知道哪個Presenter在處理。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;public partial class AddYears : System.Web.UI.UserControl,IFourthView&lt;br /&gt;{&lt;br /&gt;public event EventHandler&amp;lt;mvppresenter.eventargs&amp;gt;&amp;lt;int&amp;gt;&amp;gt; YearsAdded;&lt;br /&gt;&lt;br /&gt;protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public DateTime CurrentDateTime&lt;br /&gt;{&lt;br /&gt;   get { return DateTime.Parse(lbInitDateTime.Text); }&lt;br /&gt;   set { lbInitDateTime.Text = value.ToString(); }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void btnAddYears_Click(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;   EventArgs&lt;int&gt; args = new EventArgs&amp;lt;int&amp;gt;(1);&lt;br /&gt;&lt;br /&gt;   YearsAdded(null,args);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/int&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;參考資料&lt;/span&gt;：&lt;br /&gt;CodeProject上資源：&lt;a class="ext-link" href="http://www.codeproject.com/KB/architecture/ModelViewPresenter.aspx"&gt;&lt;span class="icon"&gt;http://www.codeproject.com/KB/architecture/ModelViewPresenter.aspx&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Matin Fowler的UI架構：&lt;a class="ext-link" href="http://martinfowler.com/eaaDev/uiArchs.html"&gt;&lt;span class="icon"&gt;http://martinfowler.com/eaaDev/uiArchs.html&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-8340760445649697354?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/8340760445649697354/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=8340760445649697354' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8340760445649697354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/8340760445649697354'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/04/mvp-patternaspnet2.html' title='MVP Pattern在ASP.NET上的應用(2)'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-6972736319827471182</id><published>2008-04-24T06:16:00.000-07:00</published><updated>2008-05-02T02:40:12.048-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>MVP Pattern在ASP.NET上的應用(1)</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;前言：&lt;br /&gt;&lt;/span&gt; 一直以來，UI的架構就存在著三種觀念。V指的是畫面，M指的是系統的資料，而如何取出必要的資料，並將傳遞給V就是C的責任，MVC是切割責任的好架 構。這裏不再介紹MVC，對MVC有興趣的人可以去玩玩ASP.NET MVC與MonoRail。那什麼是MVP?其實三者的責任也都沒變，就是實作的手法有些不同。一般Web的MVC，訊息是先送至C，再由C呼叫M，並 找出該呈現的V。而MVP，訊息還 是在V攔截，再由V發出事件通知P，P呼叫M，再回頭控制V。講理論太麻煩，請各位看一下最後的參考資料。 &lt;blockquote&gt; &lt;/blockquote&gt;     MVP Pattern被討論最廣泛的地區是這篇&lt;a class="ext-link" href="http://www.codeproject.com/KB/architecture/ModelViewPresenter.aspx"&gt;&lt;span class="icon"&gt;http://www.codeproject.com/KB/architecture/ModelViewPresenter.aspx&lt;/span&gt;&lt;/a&gt;。我之所以研究MVP Pattern是為 了找尋適用於ASP.NET的架構，又不想全面捨棄Web Form的開發方式，擁抱MVC。微軟已在Web Client Software Factory實踐了MVP，這又是大多數寫ASP.NET的人，所不知道的事。今天這篇，會推出幾種抄來的MVP的寫法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;實作：&lt;br /&gt;&lt;/span&gt;先介紹專案的架構。MVPPresenter是個單純的類別庫，IView目錄放的是每個Page或UC該實作的Interface， Presenter 目錄放的是每個Page或UC對應的P。MyMVP是個Web專案，裏頭就是放Page、UC 的地方。!MyMVP是參考MVPPresenter的。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SBCKJs5YrhI/AAAAAAAAAA0/InLJ0oi_Uzw/s1600-h/MVP1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SBCKJs5YrhI/AAAAAAAAAA0/InLJ0oi_Uzw/s320/MVP1.jpg" alt="" id="BLOGGER_PHOTO_ID_5192802269633490450" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;方法1：&lt;br /&gt;&lt;/span&gt;首先打開FirstView，我們看見這個畫面。lbInitDateTime起始是DateTime.Now。當按下增加一天時，就會把畫面上日期再加一天。辜且不論各位以前是怎麼寫這個需求，現在用MVP改寫一遍。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBCKo85YriI/AAAAAAAAAA8/HmxcR1HuUIU/s1600-h/MVP2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBCKo85YriI/AAAAAAAAAA8/HmxcR1HuUIU/s320/MVP2.jpg" alt="" id="BLOGGER_PHOTO_ID_5192802806504402466" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;首先打開FirstView，我們看見這個畫面。lbInitDateTime起始是DateTime.Now。當按下增加一天時，就會把畫面上日期再加一天。辜且不論各位以前是怎麼寫 這個需求，現在用MVP改寫一遍。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public interface IFirstView&lt;br /&gt;{&lt;br /&gt;DateTime CurrentDateTime { get;set;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; FirstPresenter.cs打開像這樣。事件處理記在這裏。P把View的事件處理完畢。再產生好的值指定給V。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt; public class FirstPresenter&lt;br /&gt;{&lt;br /&gt;private IFirstView _currentView;&lt;br /&gt;&lt;br /&gt;public FirstPresenter(IFirstView currentView)&lt;br /&gt;{&lt;br /&gt;this._currentView = currentView;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void initView(bool isPostBack)&lt;br /&gt;{&lt;br /&gt;if (!isPostBack)&lt;br /&gt;{&lt;br /&gt;_currentView.CurrentDateTime = DateTime.Now;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//View會把事件Post過來，這裏可以呼叫後端的M處理事件，完畢後，透過設定好的屬性把結果告訴View。&lt;br /&gt;public void AddDays(int days)&lt;br /&gt;{&lt;br /&gt;_currentView.CurrentDateTime = _currentView.CurrentDateTime.AddDays(1);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; 而FirstView.aspx.cs打開像這樣：&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public partial class FirstView : System.Web.UI.Page,IFirstView&lt;br /&gt;{&lt;br /&gt;private FirstPresenter myPresenter;&lt;br /&gt;&lt;br /&gt;protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;myPresenter = new FirstPresenter(this);&lt;br /&gt;myPresenter.initView(Page.IsPostBack);&lt;br /&gt;}&lt;br /&gt;//實作IFirstView&lt;br /&gt;public DateTime CurrentDateTime&lt;br /&gt;{&lt;br /&gt;get { return DateTime.Parse(lbInitDateTime.Text);}&lt;br /&gt;set { lbInitDateTime.Text = value.ToString("yyyy/MM/dd"); }&lt;br /&gt;}&lt;br /&gt;//有事件，交給P處理&lt;br /&gt;protected void btnAddDays_Click(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;myPresenter.AddDays(1);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;以上，不知各位有概念沒有。要點是Page完全只要處理如何呈現，只要介面開好會變動的部分，供P指定。而由於P只知道IView，所以Page不管是 Web Form，Windows Form，WPF Form都是一樣的。前端是用GridView，還是ListView，P一點也不關心。這個大大的增加可測試性。&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;方法2&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;：&lt;br /&gt;&lt;/span&gt; 同樣的，UserControl一樣可以為它建一個IView與Presenter。AddDays.ascx是長這樣的：&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBCMz85YrjI/AAAAAAAAABE/Y4CQeWfenQw/s1600-h/MVP3.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBCMz85YrjI/AAAAAAAAABE/Y4CQeWfenQw/s320/MVP3.jpg" alt="" id="BLOGGER_PHOTO_ID_5192805194506219058" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;打開ISecondView.cs，多了一個AttachPresenter。透過這個Method把Presenter注入。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public interface ISecondView&lt;br /&gt;{&lt;br /&gt;DateTime CurrentDateTime { get;set;}&lt;br /&gt;void AttachPresenter(SecondPresenter presenter);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;SecondPresenter幾乎沒變化。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public class SecondPresenter&lt;br /&gt;{&lt;br /&gt;private ISecondView _currentView;&lt;br /&gt;&lt;br /&gt;public SecondPresenter(ISecondView currentView)&lt;br /&gt;{&lt;br /&gt;  _currentView = currentView;&lt;br /&gt;}&lt;br /&gt;public void initView(bool isPostBack)&lt;br /&gt;{&lt;br /&gt;  if (!isPostBack)&lt;br /&gt;  {&lt;br /&gt;     _currentView.CurrentDateTime = DateTime.Now;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;public void AddDays(int days)&lt;br /&gt;{&lt;br /&gt;  _currentView.CurrentDateTime = _currentView.CurrentDateTime.AddDays(1);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; AddDays.ascx.cs是長這樣，多一個Method，接收SecondPresenter。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public partial class AddDays : System.Web.UI.UserControl,ISecondView&lt;br /&gt;{&lt;br /&gt;SecondPresenter _currentPresenter;&lt;br /&gt;&lt;br /&gt;public DateTime CurrentDateTime&lt;br /&gt;{&lt;br /&gt;   get { return DateTime.Parse(lbInitDateTime.Text); }&lt;br /&gt;   set { lbInitDateTime.Text = value.ToString(); }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void AttachPresenter(SecondPresenter presenter)&lt;br /&gt;{&lt;br /&gt;   this._currentPresenter = presenter;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void btnAddDays_Click(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;  _currentPresenter.AddDays(1);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; 回到SecondPage.aspx.cs一看，不過是為兩個牽線，並做起始的動作。&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&lt;br /&gt;protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;SecondPresenter myPresenter = new SecondPresenter(myAddDays);&lt;br /&gt;myAddDays.AttachPresenter(myPresenter);&lt;br /&gt;myPresenter.initView(IsPostBack);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-6972736319827471182?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/6972736319827471182/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=6972736319827471182' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6972736319827471182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6972736319827471182'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/04/mvp-patternaspnet1.html' title='MVP Pattern在ASP.NET上的應用(1)'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/SBCKJs5YrhI/AAAAAAAAAA0/InLJ0oi_Uzw/s72-c/MVP1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-4013689170163183611</id><published>2008-01-07T18:04:00.000-08:00</published><updated>2008-05-06T08:52:27.936-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>四色原形分析法</title><content type='html'>&lt;div class="wikipage"&gt;     &lt;div id="searchable"&gt;&lt;h2 id="前言"&gt;前言&lt;/h2&gt; &lt;blockquote&gt; &lt;p&gt; 建立Domain Model時，最令人頭痛的莫過於它建立的準則是什麼。有如在OOD時，如果沒有Design Pattern，設計也會漫無目標，人言人殊。坊間討論OOA的書不少，但涉及Domain Model的部份時，總是輕輕帶過，或者寫不出一個像樣的準則。現實世界是非常複雜的，沒有適當的準則，單憑萬物皆物件，並沒有太大的幫助。 討論Domain Model的建立過程，我發現有兩本書值得借鏡。一本是盛名已久的Analysis Pattern，一本則是Java Modeling in Color With UML。AP是各種領域塑模的心血結晶，但JMCU是建立一套推論的準則。而四色分析正是JMCU的特色。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h3 id="原型Archetypes"&gt;原型(Archetypes)&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt; 什麼是Archetypes呢?在各式的企業概念中，歷經長久的分析，可以歸類成幾種型態，象徵更抽象的概念。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h4 id="moment-intervalarchetype"&gt;moment-interval archetype&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; 簡稱mi的archetype，象徵一種與時間有關的活動。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h4 id="Partyarchetype"&gt;Party archetype&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; Party是一種人地物(party, place, or thing)的抽象概念。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h4 id="Rolearchetype"&gt;Role archetype&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; Role代表Party參予MI時的角色。即使是同一個Party但參予MI時，所使用的Role必然是有差異的。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h4 id="Description"&gt;Description&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; Desc第一種目的是Party的歸類，Party參予MI的方式也可能是一群Party，所以有時是Desc連到MI去。第二種目的是規範Party是否能變成某種Role，它是Party的Knowledge Level。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h3 id="Color"&gt;Color&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt; OO的大師Peter Coad對顏色有異乎常人的喜好，所以就把色彩設計上去了。&lt;br /&gt;MI是系統分析時的要角，我們用粉紅色表示。&lt;br /&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/R5AJrPd0Q_I/AAAAAAAAAAk/aSrMkbF8J3E/s1600-h/MI.jpg"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/R5AJrPd0Q_I/AAAAAAAAAAk/aSrMkbF8J3E/s320/MI.jpg" alt="" id="BLOGGER_PHOTO_ID_5156632211829834738" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt; Role是代表MI的主要活動角色，用次重要的黃色表示。&lt;br /&gt;&lt;/p&gt; &lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/R5AKGfd0RAI/AAAAAAAAAAs/uuspl_UaZQc/s1600-h/role.jpg"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/R5AKGfd0RAI/AAAAAAAAAAs/uuspl_UaZQc/s320/role.jpg" alt="" id="BLOGGER_PHOTO_ID_5156632679981270018" border="0" /&gt;&lt;/a&gt;&lt;blockquote&gt; &lt;p&gt; Party是一般重要性物件，用綠色表示。&lt;br /&gt;&lt;/p&gt; &lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SBrgMs5YrmI/AAAAAAAAABc/qPIT-Xct0RA/s1600-h/party.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SBrgMs5YrmI/AAAAAAAAABc/qPIT-Xct0RA/s320/party.jpg" alt="" id="BLOGGER_PHOTO_ID_5195711628940193378" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;Desc是Party的歸類，最少變動，用藍色表示。&lt;/p&gt; &lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBrgec5YrnI/AAAAAAAAABk/ndVinvLa8os/s1600-h/description.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/SBrgec5YrnI/AAAAAAAAABk/ndVinvLa8os/s320/description.jpg" alt="" id="BLOGGER_PHOTO_ID_5195711933882871410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3 id="基本分析架構"&gt;基本分析架構&lt;/h3&gt; &lt;h4 id="Ex1"&gt;Ex 1&lt;/h4&gt; &lt;p&gt; 這張圖可以代表大部分分析的最原始狀態。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SBrgrs5YroI/AAAAAAAAABs/xfUjY6i_iaI/s1600-h/Ex1.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SBrgrs5YroI/AAAAAAAAABs/xfUjY6i_iaI/s320/Ex1.jpg" alt="" id="BLOGGER_PHOTO_ID_5195712161516138114" border="0" /&gt;&lt;/a&gt;&lt;a style="border: medium none ; padding: 0pt; font-weight: bold;" href="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/%E5%9B%9B%E8%89%B2%E5%8E%9F%E5%9E%8B%E5%88%86%E6%9E%90%E6%B3%95/Ex1.jpg"&gt;&lt;br /&gt;&lt;/a&gt; &lt;/p&gt; &lt;h4 id="Ex2"&gt;Ex 2&lt;/h4&gt; &lt;p&gt; 再複雜一點，就變成這樣。先把Thing、Place、Party三種type分離出來。MI是一系列的活動過程，上一活動下一活動以及子活動。三種Party(Place、Thing)都以各自的角色參予MI。然後也都有各自的Desc。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SBrhCM5YrpI/AAAAAAAAAB0/xPrf5xDR_IM/s1600-h/Ex2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SBrhCM5YrpI/AAAAAAAAAB0/xPrf5xDR_IM/s320/Ex2.jpg" alt="" id="BLOGGER_PHOTO_ID_5195712548063194770" border="0" /&gt;&lt;/a&gt;&lt;a style="border: medium none ; padding: 0pt; font-weight: bold;" href="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/%E5%9B%9B%E8%89%B2%E5%8E%9F%E5%9E%8B%E5%88%86%E6%9E%90%E6%B3%95/Ex2.2.jpg"&gt;&lt;br /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;    &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-4013689170163183611?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/4013689170163183611/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=4013689170163183611' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4013689170163183611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4013689170163183611'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/01/blog-post.html' title='四色原形分析法'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/R5AJrPd0Q_I/AAAAAAAAAAk/aSrMkbF8J3E/s72-c/MI.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-4039588640031322335</id><published>2008-01-07T18:02:00.000-08:00</published><updated>2008-05-02T02:29:09.756-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>Analysis Pattern--Observations And Measurements(2)</title><content type='html'>&lt;h4 id="Phenomenon"&gt;Phenomenon&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; 正如字面上的意義，這個名詞代表各式的生理現象，血型A、膚色黃、有過敏、輕度憂鬱，以上我們可以說Phenomenon Type是血型、膚色、過敏、憂鬱，而Phenomenon就是(A,B,O,AB)、(黃,黑,白,紅)、(有,無)、(重度,中度,輕微)的選項。這 裏稍微把Phenomenon Type與Observation的觀念拉開，變成Measurement還是牽涉到Phenomenon Type。但Category Observation，就算放在Phenomenon是A，對照回Phenomenon Type，不會搞不清楚是血型還是肝炎。 &lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt; &lt;a style="border: medium none ; padding: 0pt;" href="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj4.jpg"&gt;&lt;img src="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj4.jpg?format=raw" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;h4 id="ObservationConcept"&gt;Observation Concept &lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt;在蒐集了大量生理資料後，接下來是進行資料的歸類。首先我們發現Category Observation中有很多有/無的選項，例如你有沒有頭痛、有沒有心臟病、有沒有過敏，為了這些有無句在Phenomenon開兩個選項太浪費，不 如留一個選項，並為Category Observation做兩個子項，Presence(有)，absent(無)。假如有就放在Presence，沒有就放在absent。&lt;br /&gt;再來我們為Phenomenon做歸類，就以頭痛來說吧，頭痛裏有張力性頭痛、偏頭痛、聚集性頭痛、竇性頭痛，頭痛是一個概念，真實的區分是另外四種。我 們提出一個Observation Concept來放這種歸類。要注意的是這五種頭痛在Phenomenon也有擺資料，但為了表現它們的歸類關係，所以在Observation Concept做關聯。Phenomenon與Observation Concept是父子關係，而Observation Concept有自我關聯多對多的關係，這意思是這不是一個樹狀圖，這是一個網狀圖。&lt;br /&gt;假如某人經觀察有偏頭痛，資料會擺在偏頭痛Presence，關聯到Observation Concept做推論，可以說這個人就是頭痛。如果沒有，那也就沒什麼意義，不能憑此推論有沒有頭痛。反過來說，如果一個人被觀察沒頭痛，關聯到 Observation Concept做推論，我們也可以說這個人沒有張力性頭痛、偏頭痛、聚集性頭痛、竇性頭痛。&lt;br /&gt;另外就是Protocal就是記錄觀察的方式，也許是透過某種儀器，或者是口頭詢問，問卷等，這些有助於我們判斷這個觀察有多少的可信度。&lt;br /&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt; &lt;a style="border: medium none ; padding: 0pt;" href="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj5.jpg"&gt;&lt;img src="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj5.jpg?format=raw" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;h4 id="RejectedObservation"&gt;Rejected Observation &lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; 在眾多的觀察數據中，撇開儀器失靈這種可怕的失誤，很多時候會是人為的誤判。例如斷定你是感冒，給你吃了好幾天的藥，過一段時間，才發現是登革熱。在資訊 記錄上，當然不可能把當時的資料蓋掉，畢竟藥都吃了好幾天，這是有記錄的。此時另開一個Table來存曾經失誤的數據的，是很自然的想法，我們叫它 Rejected Observation。這一章節，Observation一直沒動，但它衍生的概念，一個個變成繼承的類別。我們在處理需求異動時，資料庫固然經常性的 增加欄位，但有時已經代表新的概念的出現，獨立開一個Table似無不可。而在程式設計上，在不動原來類別情況下，用繼承來處理新概念，可以減少系統的異 動幅度。&lt;br /&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt; &lt;a style="border: medium none ; padding: 0pt;" href="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj6.jpg"&gt;&lt;img src="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj6.jpg?format=raw" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;h4 id="AssociatedObservation"&gt;Associated Observation&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; 在收集這麼多數據後，終於進入臨床診斷。根據觀察，這個人有口渴、體重減輕、頻尿的狀況，依據這些狀況，醫生猜是糖尿病，但缺少證據。於是做了個證據的觀 察，例如血糖量測。Observation就是糖尿病，Associated Observation就是血糖量測，可以證明這是糖尿病。在Knowledge Level，Obsevation Concept中，糖尿病、口渴、體重減輕、頻尿都是Observation Concept。而Associative Function就是為徵狀與疾病拉上判斷式，有這幾種徵狀，應該就是糖尿病。如果再有來幾個佐證的觀察，就是一次完整的臨床判斷。&lt;br /&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt; &lt;a style="border: medium none ; padding: 0pt;" href="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj7.jpg"&gt;&lt;img src="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/ObserAndMea/obj7.jpg?format=raw" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-4039588640031322335?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/4039588640031322335/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=4039588640031322335' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4039588640031322335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/4039588640031322335'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/01/analysis-pattern-observations-and_07.html' title='Analysis Pattern--Observations And Measurements(2)'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-312896008262330922</id><published>2008-01-01T23:29:00.000-08:00</published><updated>2009-08-05T09:38:18.385-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>Analysis Pattern--Observations And Measurements(1)</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;前言&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;對於醫療系統，量測資訊的記錄是一個非常重要的事。所謂的量測資訊，並不只是儀器量出來的數據，更多是像選擇題般的歸納數據。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Quantity&lt;/span&gt;&lt;br /&gt;量測會產生各式各樣的數據，但數據並非只是單純的阿拉伯數字，它是一個量(Quantity)，由一個數字加一個單位組成。如圖：&lt;br /&gt;&lt;br /&gt;&lt;img src="file:///C:/Users/user/AppData/Local/Temp/moz-screenshot-7.jpg" alt="" /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/R3s-v_d0Q8I/AAAAAAAAAAM/STS8UoOiNPE/s1600-h/obj1.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/R3s-v_d0Q8I/AAAAAAAAAAM/STS8UoOiNPE/s320/obj1.jpg" alt="" id="BLOGGER_PHOTO_ID_5150779593039561666" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;在POEAA(488)有討論到Money的用法，我們可以用相同的方式理解。Quantity物件的好處，第一是方便比較，例如30kg &gt; 100g、第二控制乘除後的精度、第三可以控制呈現的格式。我們可能會設計出高度Quantity，重量的Qunatity，時間的Quantity。以及英吋、台斤、光年各種單位。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;Class HeightQuantity&lt;br /&gt;{&lt;br /&gt;int height&lt;br /&gt;HeightUnit unit;&lt;br /&gt;&lt;br /&gt;// Quantity物件可以比較&lt;br /&gt;public int CompareTo(object obj){&lt;br /&gt;   HeightQuantity other = (HeightQuantity)obj;&lt;br /&gt;&lt;br /&gt;   if ((other.Unit).Equals(this.Unit)){&lt;br /&gt;       return (int)Math.Ceiling(this.Height - other.Height);&lt;br /&gt;   }&lt;br /&gt;   else{&lt;br /&gt;       return  (int)Math.Ceiling(this.Height - other.Height * ConversionRatio.getRatio(other.Unit, this.Unit) );&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;// 當然長度的相乘是面積，大家來想該怎麼寫。而且有時相乘後的數值，該取小數點幾位，是看實際狀況的。&lt;br /&gt;public HeightQuantity Multiply(decimal multiplier){&lt;br /&gt;   return new HeightQuantity(this.Height * multiplier, this.Unit * this.Unit);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// 控制輸出的文字&lt;br /&gt;public override string ToString(){&lt;br /&gt;   return this.Height.ToString() +  _unit.ToString();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Enum HeightUnit{&lt;br /&gt;cm = 0,&lt;br /&gt;m = 1&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Class ConversionRatio{&lt;br /&gt;static decimal[,] _ratio = new decimal[2, 2] { { 1, 0.01M }, { 100, 1 } };&lt;br /&gt;public static decimal getRatio(HeightUnit from, HeightUnit to){&lt;br /&gt;   return _ratio[(int)from, (int)to];&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestCompare(){&lt;br /&gt;Measurements.HeightQuantity AObject = new Measurements.HeightQuantity(5M, HeightUnit.m);&lt;br /&gt;Measurements.HeightQuantity BObject = new Measurements.HeightQuantity(50M, HeightUnit.cm);&lt;br /&gt;&lt;br /&gt;Assert.Greater(AObject, BObject);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestMultiply(){&lt;br /&gt;Measurements.HeightQuantity AObject = new Measurements.HeightQuantity(5M, HeightUnit.m);&lt;br /&gt;Measurements.HeightQuantity BObject = AObject.Multiply(1.5M);&lt;br /&gt;&lt;br /&gt;Assert.AreEqual(BObject, new HeightQuantity(7.5M, HeightUnit.m));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestPresent(){&lt;br /&gt;Measurements.HeightQuantity AObject = new Measurements.HeightQuantity(5M, HeightUnit.m);&lt;br /&gt;&lt;br /&gt;Assert.AreEqual(AObject.ToString(), "5m");&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Measurement &lt;/span&gt;&lt;br /&gt;量測檔measurement，就是針對某個人，進行儀器的量測，並留下量測數據，當然這個數據在程式中必須以Quantity的概念呈現。而 Quantity在資料庫的存取方式可參考POEAA(268)的Embed value。而Phenomenon Type就是量測項目檔。&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/R3s_D_d0Q9I/AAAAAAAAAAU/qAkmUGw77mU/s1600-h/obj2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/R3s_D_d0Q9I/AAAAAAAAAAU/qAkmUGw77mU/s320/obj2.jpg" alt="" id="BLOGGER_PHOTO_ID_5150779936636945362" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Observation&lt;/span&gt;&lt;br /&gt;量測談的是有數據的量測，但人的生理狀況並非全然都能用數字表達。例如血型，憂鬱程度(重度、中度、輕微)、像選擇題似的問法。這些也是人生理狀況的一種，我們將這兩種情形，統一用一個概念表示，叫Observation。我可以說選擇題的答案是放在Category Observation，選擇題的問項是放在Category。像這種有繼承觀念，用OO的思考甚易理解，但在資料庫的對應上，就得注意，假如是 Observation、Measurement、Category Observation各開一個Table，Observation的PK，就是Measurement與Category Observation的PK，顯示這是IS-a的關係。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cvihUH5Nlq8/R3s_dPd0Q-I/AAAAAAAAAAc/5eQU22CKF0s/s1600-h/obj3.jpg"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_cvihUH5Nlq8/R3s_dPd0Q-I/AAAAAAAAAAc/5eQU22CKF0s/s320/obj3.jpg" alt="" id="BLOGGER_PHOTO_ID_5150780370428642274" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-312896008262330922?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/312896008262330922/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=312896008262330922' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/312896008262330922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/312896008262330922'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2008/01/analysis-pattern-observations-and.html' title='Analysis Pattern--Observations And Measurements(1)'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/R3s-v_d0Q8I/AAAAAAAAAAM/STS8UoOiNPE/s72-c/obj1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3083392636083317507</id><published>2007-12-23T20:13:00.000-08:00</published><updated>2008-05-02T02:32:07.261-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開發流程'/><title type='text'>FDD--敏捷方法論</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;前言&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt; 隨著軟體複雜度的增加，傳統的瀑布式開發早就不合時代的需要。往往系統還在分析階段，使用者的需求就翻了兩番，連技術也加了好幾種，需求凍結的時間變的遙 遙無期。合理的想法，就是儘量縮短開發的時間，以及使用迭代式的開發反覆的逼近使用者的需求。以這種想法我發現敏捷方法論相當合乎我的理念，代表敏捷方法 論有XP、Scrum、FDD、ICONIX、DSD等，由於Agile Management這本書的啟發，使得我對FDD較有興趣。尤其是它所標榜的時程預估的精確性，以及大專案的擴充性。 &lt;/p&gt; &lt;/blockquote&gt; &lt;span style="font-size:130%;"&gt;簡介&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;FDD完整稱呼是Feature-Driven Development。Use-Case Driven、Model Driven也許大家都聽過，那什麼是Feature-Driven呢?Feature-Driven本質上還是Model Driven，是先規劃出整套的Domain Model，做為系統起始的核心。接下來就是依據Model，開始找出所有的Feature。而Feature = 可以為客戶產生價值的最小開發單位。群集後的Feature稱之為Feature Set。而系統的某一個主題領域就是組合了很多Feature Set。接下來，專案經理就是依據Feature來規畫開發的週期，書上建議每次的週期是兩週，所以每個Feature必然不可以超過兩週，會超過兩週的 Feature必須再予以細分。所謂兩週內的工作，包含為這個Feature設計、開發、測試、佈置。 &lt;/p&gt; &lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;名詞解釋 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Feature&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt; 簡介說Feature = 可以為客戶產生價值的最小開發單位，到底是什麼意義，依書上的說法，為一個Feature定義一個樣版敘述：&lt;/p&gt;&lt;p&gt;&amp;lt;action&amp;gt; the &amp;lt;result&amp;gt; &amp;lt;by|for|of|to&amp;gt; a(n) &amp;lt;object&amp;gt;&lt;/p&gt;&lt;p&gt; 呃，為了領域模型中的某類別，執行某種行為，產生一種結果。&lt;br /&gt;例如： &lt;/p&gt; &lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;ol&gt;&lt;li&gt;Calculate the total of a sale &lt;/li&gt;&lt;li&gt;Assess the fulfillment timeliness of a sale &lt;/li&gt;&lt;li&gt;Caculate the total purchases by a customer &lt;/li&gt;&lt;/ol&gt;&lt;p&gt; sale、customer都是領域類別，Calculate、Assess可能是一個Method，結果可能是再產生一個物件，也可能只是改變某個值。 &lt;/p&gt; &lt;span style="font-size:100%;"&gt;Feature Set&lt;/span&gt; &lt;blockquote&gt; &lt;p&gt; 一個商業活動包含很多Feature，我們叫Feature Set，樣版敘述如下：&lt;br /&gt;&lt;/p&gt; &lt;p&gt;&amp;lt;action&amp;gt;&amp;lt;-ing&amp;gt; a(n) &amp;lt;object&amp;gt;&lt;/p&gt;&lt;p&gt; 因為是某活動，所以有ing。&lt;br /&gt;例如： &lt;/p&gt; &lt;/blockquote&gt; &lt;ol&gt;&lt;li&gt;Making a Product sale to a customer &lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:100%;"&gt;Subject Area &lt;/span&gt; &lt;blockquote&gt; &lt;p&gt; 再來很多商業活動就要一個主題了，樣版敘述如下：&lt;br /&gt;&lt;/p&gt; &lt;p&gt;&amp;lt;object&amp;gt; management&lt;/p&gt;&lt;p&gt; 例如： &lt;/p&gt; &lt;/blockquote&gt; &lt;ol&gt;&lt;li&gt;Product-sales management &lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:130%;"&gt;流程&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;Process 1: Develop an Overall Model&lt;/span&gt; &lt;p&gt; 所謂的Model，在此定義，就是一種圖。描述Problem Domain，用的是Domian Model。描述UI的，FDD使用State Chart。 &lt;/p&gt; &lt;p&gt;製作Domain Model的工作是由主架構師與領域專家共同討論出來的，我想也未必是領域專家，或許是專案中最重點的人物。製作Domain Model當然需要很高的軟體抽象能力，還得兼備理解多重領域語言的能力。Domain Model是在分析系統會出現的概念，這裏重點是為了建造一個完整的模型，並為了與所有的參與者進行溝通的重要步驟。關於建立Domain Model，可以看Matin Fowler的「Analysis Pattern」、Peter Coad的「Java Modeling With Color In UML」。 &lt;/p&gt; &lt;p&gt; State Chart的來源可以來自簡單的手繪或ProtoType，亦可幫助參與者理解UI的運作流程。  &lt;/p&gt; &lt;span style="font-size:100%;"&gt;Process 2: Build a Features List&lt;/span&gt; &lt;p&gt;在做出整個Model圖之後，便是由圖形中推論出所有的Feature。這個工作是由主工程師及專案經理來做。推論出來的Feature對使用者來 說是可以理解的，是專案經理要負責追蹤進度，擔保完成。而主工程師則是取出Feature，並大略將Feature細拆成兩週以下的工作。 &lt;/p&gt; &lt;p&gt; UI的Feature，可以從StateChart拆成View、Event以及Transient Business Features，例如檢查身分證字號或者是列出客戶資料，不過這部分的資料我還不確定。 &lt;/p&gt; &lt;p&gt; FDD有提供一個粗略的表，幫助主工程師為每一個Feature打分數。 &lt;/p&gt; &lt;table class="wiki"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Weight&lt;/td&gt;&lt;td&gt;Man Days &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;         1/2 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;         1 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;         2 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;         4 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;         8+ &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&lt;br /&gt;&lt;/p&gt; &lt;table class="wiki"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Weight&lt;/td&gt;&lt;td&gt;Classes touched &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;         1 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;         2 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;         3 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;         4 &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;         5 or more &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;span style="font-size:100%;"&gt;Process 3: Plan By Feature&lt;/span&gt; &lt;p&gt;接下來就是專案經理的工作，哪些Feature Set是優先完成，哪些還可以等等，一次週期是兩週。之所以是兩週，是因為週會議上可以檢討一週進度，通常很容易檢視執行的狀況，如果專案產生延遲的狀 況，可以在迭代進行一半時砍掉來不及的工作，也可以檢討這次迭代工作的得失。 &lt;/p&gt; &lt;span style="font-size:100%;"&gt;Process 4: Design By Feature&lt;/span&gt; &lt;p&gt;到此工作才進入迭代的範圍。這應該讓人感到質疑，這是什麼迭代開發、敏捷方法。所謂的迭代，應該在是包含分析、設計、Coding、Test、 Build的一個循環，怎麼縮水成設計、Coding、Test、Build。這樣如何擁抱改變，產生最大的靈活度?這只好請各位請找創始人去問一下。基 本上最初的分析工作也不是不可變動的，在迭代過程還是可以回頭修正我們的Model，但修正是否會波及整個最初的估算，這就不是我能回答的事。當然FDD 也被視為游走在傳統方法論與新式迭代開發方法論之間。 &lt;/p&gt; &lt;span style="font-size:100%;"&gt;Process 5: Build By Feature&lt;/span&gt; &lt;p&gt; 設計完畢才是進入開發階段，開發包含Coding、Test、Build，這步才是我們大部分日常的工作。  &lt;/p&gt; &lt;span style="font-size:130%;"&gt;參考資料&lt;br /&gt;&lt;/span&gt;&lt;a class="ext-link" href="http://www.nebulon.com/fdd/index.html%EF%BC%9AFDD"&gt;&lt;span class="icon"&gt;http://www.nebulon.com/fdd/index.html：FDD&lt;/span&gt;&lt;/a&gt;的流程定義  &lt;p&gt; &lt;a class="ext-link" href="http://www.featuredrivendevelopment.com/"&gt;&lt;span class="icon"&gt;http://www.featuredrivendevelopment.com/&lt;/span&gt;&lt;/a&gt; ：FDD的論壇 &lt;/p&gt; &lt;p&gt; &lt;a class="ext-link" href="http://en.wikipedia.org/wiki/Feature_Driven_Development"&gt;&lt;span class="icon"&gt;http://en.wikipedia.org/wiki/Feature_Driven_Development&lt;/span&gt;&lt;/a&gt; ：Wiki上的介紹 &lt;/p&gt; &lt;p&gt; &lt;a class="ext-link" href="http://conferences.codegear.com/tw/article/32095"&gt;&lt;span class="icon"&gt;http://conferences.codegear.com/tw/article/32095&lt;/span&gt;&lt;/a&gt; ：如果你胃口不錯，就來看FDD建立Domain Model的方法，很實務的做法 &lt;/p&gt; &lt;p&gt; &lt;a class="ext-link" href="http://www.uidesign.net/2001/papers/fddui.html#Anderson00"&gt;&lt;span class="icon"&gt;http://www.uidesign.net/2001/papers/fddui.html#Anderson00&lt;/span&gt;&lt;/a&gt; ：介紹使用State Chart，以及UI的Feature如何撰寫 &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3083392636083317507?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3083392636083317507/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3083392636083317507' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3083392636083317507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3083392636083317507'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2007/12/fdd.html' title='FDD--敏捷方法論'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-3767096993611101086</id><published>2007-12-12T19:46:00.000-08:00</published><updated>2009-08-05T09:41:26.420-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='工具'/><title type='text'>MS Build使用介紹</title><content type='html'>&lt;span style="font-weight: bold;"&gt;前言&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;MsBuild是一套類似Nant的工具，而Nant是Java ant的仿製版。在開發的過程中，Coding完畢後，一般就是Pg自行編譯測試，送上SourceControl。所有的Code雖然都在 SourceControl，要測試時，不免又要取得全部的Code，建置，移動必要檔案。測試資料重建，文件重建，讓測試人員随時Ready測試。種種繁瑣的動作，實在不適合人為擔任。類似ant工具的想法，就是把一堆工作用XML寫下來，呼叫工具執行，這樣軟體開發才有工業化的流程，不要幫別人自動化，自己還在過手工業的日子&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;快速使用&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;MsBuild已經是.NET 2.0的內建工具，不必另外下載。寫一個小程式如下：&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;namespace TestMsBuild{&lt;br /&gt;class Program{&lt;br /&gt;static void Main(string[] args){&lt;br /&gt;Program thisProg = new Program();&lt;br /&gt;thisProg.WriteMessage();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void WriteMessage(){&lt;br /&gt;Console.WriteLine("Hello MsBuild");&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;MsBuild的建置配置檔，必須以*.*proj的檔名，以XML的格式儲存。示範的proj與.sln擺在一起。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;Project Defaulttargets="Run" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&amp;gt;&lt;br /&gt;&amp;lt;!--PropertyGroup名稱是固定的，裏頭擺的是自建的變數--&amp;gt;&lt;br /&gt;&amp;lt;PropertyGroup&amp;gt;&lt;br /&gt;&amp;lt;!--這兩個Tag是自己取名的--&amp;gt;&lt;br /&gt;&amp;lt;OutputPath&amp;gt;output&amp;lt;/OutputPath&amp;gt;&lt;br /&gt;&amp;lt;OutputAssembly&amp;gt;HelloMSBuild&amp;lt;/OutputAssembly&amp;gt;&lt;br /&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- 同PropertyGroup的含義--&amp;gt;&lt;br /&gt;&amp;lt;ItemGroup&amp;gt;&lt;br /&gt;&amp;lt;CSFile include="TestMsBuild\Program.cs"/&amp;gt;&lt;br /&gt;&amp;lt;/ItemGroup&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Target Name="Build"&amp;gt;&lt;br /&gt;&amp;lt;!-- 看名字也知道在幹什麼 --&amp;gt;&lt;br /&gt;&amp;lt;MakeDir directories="$(OutputPath)" condition="!Exists('$(OutputPath)')"/&amp;gt;&lt;br /&gt;&amp;lt;Csc sources="@(CSFile)" targettype="exe" outputassembly="$(OutputPath)\$(OutputAssembly).exe"/&amp;gt;&lt;br /&gt;&amp;lt;/Target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--進來的第一個工作是Run，見上面的DefaultTargets，但跑Run之前是Build喔--&amp;gt;&lt;br /&gt;&amp;lt;Target Name="Run" DependsOnTargets="Build"&amp;gt;&lt;br /&gt;&amp;lt;Exec command="$(OutputPath)\$(OutputAssembly).exe"/&amp;gt;&lt;br /&gt;&amp;lt;/Target&amp;gt;&lt;br /&gt;&amp;lt;/Project&amp;gt;&lt;/code&gt;&lt;/pre&gt;微軟給的Task種類很少，基本的MKDIR、COPY、CSC、VBC而己，但它提供良好自建Task功能，也有開放社群幫它建Task喔。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;其他支援 &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;各位可以到這兩個地方，下載其他的Task：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msbuildtasks.tigris.org/"&gt;http://msbuildtasks.tigris.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.codeplex.com/sdctasks"&gt;http://www.codeplex.com/sdctasks &lt;/a&gt;：這個支援不少微軟的工具，如SandCastle、TFS、MS Unit Test&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;範例 &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;這是比較大的範例，我用上sdctasks，但Nunit測的有問題。再來如果想做到自動化建置測試，建議要跟CC.NET一齊使用喔。&lt;br /&gt;&lt;pre style="background-color: lightgray;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;Project DefaultTargets="PrepareDemoData" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--這裏要註冊Task--&amp;gt;&lt;br /&gt;&amp;lt;Import Project="Microsoft.Sdc.Common.tasks"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;PropertyGroup&amp;gt;&lt;br /&gt;&amp;lt;WebSite&amp;gt;TestAutoBuild&amp;lt;/WebSite&amp;gt;&lt;br /&gt;&amp;lt;WebSitePath&amp;gt;C:\inetpub\wwwroot\TestAutoBuild&amp;lt;/WebSitePath&amp;gt;&lt;br /&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;ItemGroup&amp;gt;&lt;br /&gt;&amp;lt;SourcePage Include="TestAutoBuild\*.aspx;TestAutoBuild\Web.config"/&amp;gt;&lt;br /&gt;&amp;lt;SourceDll Include="TestAutoBuild\bin\*.dll"/&amp;gt;&lt;br /&gt;&amp;lt;SourceImage Include="TestAutoBuild\Images\*.*"/&amp;gt;&lt;br /&gt;&amp;lt;SourceImagePets Include="TestAutoBuild\Images\Pets\*.*"/&amp;gt;&lt;br /&gt;&amp;lt;/ItemGroup&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Target Name="Compile"&amp;gt;&lt;br /&gt;&amp;lt;!--直接Compile .sln檔--&amp;gt;&lt;br /&gt;&amp;lt;MSBuild Projects="TestAutoBuild.sln" Properties="Configuration=Debug" /&amp;gt;&lt;br /&gt;&amp;lt;/Target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Target Name="CreateWebSite" DependsOnTargets="Compile"&amp;gt;&lt;br /&gt;&amp;lt;MakeDir Directories="$(WebSitePath)" Condition="\!Exists('$(WebSitePath)')" /&amp;gt;&lt;br /&gt;&amp;lt;MakeDir Directories="$(WebSitePath)\bin" Condition="\!Exists('$(WebSitePath)\bin')" /&amp;gt;&lt;br /&gt;&amp;lt;MakeDir Directories="$(WebSitePath)\Images" Condition="\!Exists('$(WebSitePath)\Images')" /&amp;gt;&lt;br /&gt;&amp;lt;MakeDir Directories="$(WebSitePath)\Images\Pets" Condition="\!Exists('$(WebSitePath)\Images\Pets')" /&amp;gt;&lt;br /&gt;&amp;lt;\!--建立網站應用程式--&amp;gt;&lt;br /&gt;&amp;lt;Web.WebSite.CreateVirtualDirectory&lt;br /&gt;                    VirtualDirectoryName="$(WebSite)"&lt;br /&gt;                    Path="$(WebSitePath)"&lt;br /&gt;                    MachineName="hugo"&lt;br /&gt;                    AppPoolID="Classic .NET AppPool"&lt;br /&gt;                    AppCreate="true"&lt;br /&gt;                    WebSiteName="Default Web Site"&lt;br /&gt;  AnonymousUserName="IUSR"&lt;br /&gt;                    AnonymousUserPassword=""&lt;br /&gt;                    UncUserName=""&lt;br /&gt;                    /&amp;gt;&lt;br /&gt;&amp;lt;/Target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Target Name="CopyFile" DependsOnTargets="CreateWebSite"&amp;gt;&lt;br /&gt;&amp;lt;\!--就是拷貝了--&amp;gt;&lt;br /&gt;&amp;lt;Copy&lt;br /&gt;SourceFiles="@(SourcePage)"&lt;br /&gt;DestinationFolder="$(WebSitePath)"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&amp;lt;Copy&lt;br /&gt;SourceFiles="@(SourceDll)"&lt;br /&gt;DestinationFolder="$(WebSitePath)\bin"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&amp;lt;Copy&lt;br /&gt;SourceFiles="@(SourceImage)"&lt;br /&gt;DestinationFolder="$(WebSitePath)\Images"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&amp;lt;Copy&lt;br /&gt;SourceFiles="@(SourceImagePets)"&lt;br /&gt;DestinationFolder="$(WebSitePath)\Images\Pets"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&amp;lt;/Target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Target Name="PrepareDemoData" DependsOnTargets = "CopyFile"&amp;gt;&lt;br /&gt;&amp;lt;!--執行Sql語法，把要測試的資料新增進去--&amp;gt;&lt;br /&gt;&amp;lt;Sql.Execute&lt;br /&gt;ConnectionString="Data Source=.;Initial Catalog=MSPetShop;User ID=xxxxx;Password=xxxxxxxx"&lt;br /&gt;CommandTimeout="1000"&lt;br /&gt;sql="Insert Product values('AAAAA','Dogs','Worm',null)"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/Target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--可惜Nunit失敗--&amp;gt;&lt;br /&gt;&amp;lt;/Project&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-3767096993611101086?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/3767096993611101086/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=3767096993611101086' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3767096993611101086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/3767096993611101086'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2007/12/ms-build.html' title='MS Build使用介紹'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-6788583671895833276</id><published>2007-12-09T19:41:00.000-08:00</published><updated>2008-05-02T02:30:33.413-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='工具'/><title type='text'>Watin-Web Test Framework介紹</title><content type='html'>&lt;div class="wikipage"&gt;     &lt;div id="searchable"&gt;&lt;h3 id="簡介"&gt;簡介：&lt;/h3&gt; &lt;p&gt; 　　開發網頁的過程中，免不了點點按按，測試功能是否正常。如果能把這種這些動作寫成腳本，不但能證明功能正常，也能減少時間的浪費。OpenSource中有幾套好用的工具，可以幫助我們完成這些事，如 &lt;/p&gt; &lt;ol&gt;&lt;li&gt;NUnitASP(&lt;a class="ext-link" href="http://nunitasp.sourceforge.net/"&gt;&lt;span class="icon"&gt;http://nunitasp.sourceforge.net/&lt;/span&gt;&lt;/a&gt;)： NUnitASP走的是Server端的測試，所以和瀏覽器的種類無關。必須用.NET的語言撰寫測試程式，也無法捕捉Frame、Popup的Client端行為。 &lt;/li&gt;&lt;/ol&gt;&lt;ol start="2"&gt;&lt;li&gt;Selenium(&lt;a class="ext-link" href="http://www.openqa.org/"&gt;&lt;span class="icon"&gt;http://www.openqa.org/&lt;/span&gt;&lt;/a&gt;)： 這是一套功能強大跨平台UI測試工具，包含記錄使用者操作為測試腳本的功能。 &lt;/li&gt;&lt;/ol&gt;&lt;ol start="3"&gt;&lt;li&gt;Watin(&lt;a class="ext-link" href="http://watin.sourceforge.net/"&gt;&lt;span class="icon"&gt;http://watin.sourceforge.net/&lt;/span&gt;&lt;/a&gt;)： 只能用在IE上，直接捕捉Client的行為。使用.NET的語言撰寫測試，但也有一套WatinTestRecorder可以記錄使用者的操作。 &lt;/li&gt;&lt;/ol&gt;&lt;blockquote&gt; &lt;p&gt; 　今天主要介紹Watin。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h3 id="使用方法"&gt;使用方法：&lt;/h3&gt; &lt;p&gt; 　1.安裝WatiN-1.1.2.4000-net-2.0,msi &lt;/p&gt; &lt;p&gt; 　2. 打開Vs.Net2005，新建一個Console專案。 &lt;/p&gt; &lt;p&gt; 　3. 加入Watin.core參考 &lt;/p&gt; &lt;p&gt; 　4. 在Main中加入測試碼 &lt;/p&gt;&lt;pre&gt;&lt;code&gt;[STAThread]&lt;br /&gt;public static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;//打開IE&lt;br /&gt;IE ie = new IE("http://localhost:51817/Default.aspx");&lt;br /&gt;&lt;br /&gt;//輸入帳號密碼&lt;br /&gt;ie.TextField(Find.ById("txtAccount")).TypeText("hugo");&lt;br /&gt;ie.TextField(Find.ById("txtPassword")).TypeText("....");&lt;br /&gt;&lt;br /&gt;//登入&lt;br /&gt;ie.Button(Find.ByValue("確定")).Click();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;  &lt;p&gt;以上是目前我正在進行的專案，所寫的一小段測試碼。&lt;/p&gt; &lt;blockquote&gt; &lt;/blockquote&gt; &lt;h3 id="整合NUnit"&gt;整合NUnit &lt;/h3&gt;[TestFixture]&lt;br /&gt;&lt;pre&gt;&lt;code&gt;public class Program&lt;br /&gt;{&lt;br /&gt; public static void Main(string[] args)&lt;br /&gt; {&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; [Test]&lt;br /&gt; public void TestFunction()&lt;br /&gt; {&lt;br /&gt;     //打開IE&lt;br /&gt;     IE ie = new IE("http://localhost:51817/Default.aspx");&lt;br /&gt;&lt;br /&gt;     //輸入帳號密碼&lt;br /&gt;     ie.TextField(Find.ById("txtAccount")).TypeText("hugo");&lt;br /&gt;     ie.TextField(Find.ById("txtPassword")).TypeText("xxxx");&lt;br /&gt;&lt;br /&gt;     //登入&lt;br /&gt;     ie.Button(Find.ByValue("確定")).Click();&lt;br /&gt;&lt;br /&gt;     //選擇菜單，移至所選的功能頁面&lt;br /&gt;     Assert.AreEqual("驗證失敗",ie.Span(Find.ById("lbMessage")).Text);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;然後在產生的exe同目錄下，建立與程式同名的.config檔，如下&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;lt;configSections&amp;gt;&lt;br /&gt; &amp;lt;sectionGroup name="NUnit"&amp;gt;&lt;br /&gt;  &amp;lt;section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/&amp;gt;&lt;br /&gt; &amp;lt;/sectionGroup&amp;gt;&lt;br /&gt;&amp;lt;/configSections&amp;gt;&lt;br /&gt;&amp;lt;NUnit&amp;gt;&lt;br /&gt; &amp;lt;TestRunner&amp;gt;&lt;br /&gt;  &amp;lt;!-- Valid values are STA,MTA. Others ignored. --&amp;gt;&lt;br /&gt;  &amp;lt;add key="ApartmentState" value="STA" /&amp;gt;&lt;br /&gt; &amp;lt;/TestRunner&amp;gt;&lt;br /&gt;&amp;lt;/NUnit&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;/pre&gt;打開NUnit，我們已經整合了單元測試與UI Test&lt;br /&gt;&lt;p&gt; &lt;a style="border: medium none ; padding: 0pt;" href="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/Watin/NUnit.jpg"&gt;&lt;img src="http://localhost:8000/The_Martian_Chronicles/attachment/wiki/Watin/NUnit.jpg?format=raw" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;    &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-6788583671895833276?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/6788583671895833276/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=6788583671895833276' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6788583671895833276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6788583671895833276'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2007/12/watin-web-test-framework.html' title='Watin-Web Test Framework介紹'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-7661942873276917417</id><published>2007-12-03T01:45:00.000-08:00</published><updated>2008-07-21T22:48:53.432-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>Analysis Pattern--Organization Structures(2)</title><content type='html'>&lt;h4&gt;設計五&lt;/h4&gt; &lt;p&gt;  到了設計四，描述單一組織，混合了人員與部門，看來是足夠了，但如果有很多組織呢?那在Party的Table，每個人員或部門豈不是變成多重的上級單位 或下級單位。所以又引導出新的設計，這裏導入一個新名詞叫Accountability。這個新類別負責記錄各種組織樹，並與原來的Party類別關聯。 本身帶有一個Type的屬性，與Accountability Type做關聯。資料庫的設計上，Accountability這個新Table，與原Party與一對多的關聯，有記錄上下層關係的PartyNo欄 位。而該組織的情報，我們另開一個Accountability Type的Table做記錄，它在Accountability的Foreign Key，我們另開一個欄位type來做關聯。 &lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cvihUH5Nlq8/SIV0ZrdNkOI/AAAAAAAAADk/IEUqCx7XXlY/s1600-h/obj5.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_cvihUH5Nlq8/SIV0ZrdNkOI/AAAAAAAAADk/IEUqCx7XXlY/s320/obj5.jpg" alt="" id="BLOGGER_PHOTO_ID_5225710927144128738" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;&lt;a name="AnalysisPattern--OrganizationStructures- 設計六"&gt;&lt;/a&gt; 設計六&lt;/h4&gt;  &lt;p&gt;  篇最後，我們要導入一個高階的觀念Knowledge Level。假想一種情況吧，Party原本是人員與部門的集合，但擴展一步想，客戶、廠商也可以納入我們的Party。假如他們對本公司也有一個對應的 窗口，所以加入了我們的Accountability。並設計了兩個Accountability Type，一個是廠商窗口關係，一個是客戶窗口關係，依據設計五，我們規畫出了各別的對應人員(Or 部門)。畫面輸入畫面是這樣開的，先撈Party中的員工，還有Party中的客戶，選擇完畢，再存入資料庫，真是完美的工作。好吧，今天我們不要介面， 就開個WebService好了，函數名稱就叫AddAccountability，像這樣：&lt;/p&gt; void AddAccountability(PartyType 公司窗口,PartyType 對口單位,Accountability RelationType)&lt;br /&gt;&lt;pre&gt;&lt;code&gt;{&lt;br /&gt;&lt;span class="code-keyword"&gt;switch&lt;/span&gt; RelationType&lt;br /&gt;{&lt;br /&gt;&lt;span class="code-keyword"&gt;case&lt;/span&gt; 客戶關係:&lt;br /&gt;&lt;span class="code-keyword"&gt;if&lt;/span&gt;((公司窗口is 員工Type) And (對口單位 is 客戶Type))&lt;br /&gt;{&lt;br /&gt;&lt;span class="code-comment"&gt;//存入資料庫&lt;br /&gt;&lt;/span&gt;    }&lt;br /&gt;&lt;span class="code-keyword"&gt;break&lt;/span&gt;;&lt;br /&gt;&lt;span class="code-keyword"&gt;case&lt;/span&gt; 廠商關係:&lt;br /&gt;&lt;span class="code-keyword"&gt;if&lt;/span&gt;((公司窗口is 員工Type) And (對口單位 is 廠商Type))&lt;br /&gt;{&lt;br /&gt;&lt;span class="code-comment"&gt;//存入資料庫&lt;br /&gt;&lt;/span&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;這樣也沒錯，只是有一天上級宣佈，客戶的窗口不是員工了，我們特別找了合作夥伴，由他們來服務客戶(好爛的例子)，這時上下層的關係對應不再是員工 對客戶，而是合作廠商對客戶，所以我們必須改寫我們的Code。還是先來看Knowledge Level的定義，它是一種資料比較固定的物件，放的是Operation Level的規則。而Operation Level放的是會一直產生的資料，請看圖。&lt;/p&gt;  &lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SIV0p5HZecI/AAAAAAAAADs/WEzwBp0myoI/s1600-h/obj6.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SIV0p5HZecI/AAAAAAAAADs/WEzwBp0myoI/s320/obj6.jpg" alt="" id="BLOGGER_PHOTO_ID_5225711205688637890" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;我們已有了一個Party的類別，放著所有參與有責任關係的物件，我們把它分成數種Party Type，例如廠商、客戶、員工。Connection Rule存放著各種PartyType的上下對應關係。當我們想要加入一條Accountabilty時，透過Accountabilty Type，可以查出傳入的兩種Party Type是否符合規則。所以像Accountability會隨著時間增加異動的，Party會不斷增加的，我們叫Operation Level。而規範著Operation Level的就是Knowledge Level。這個觀念在之後都會一直用到，這裏我們只要記得，把固定的資料和經常變動的資料分開擺，可以增加系統的彈性。&lt;br /&gt;&lt;/p&gt;void AddAccountability(PartyType 委任方,PartyType 責任方,AccountabilityType RelationType)&lt;br /&gt;&lt;pre&gt;{&lt;br /&gt;&lt;span class="code-comment"&gt;//RelationType裏頭有存規則，所以不用寫死在程式中了&lt;br /&gt;&lt;/span&gt;     &lt;span class="code-keyword"&gt;if&lt;/span&gt;(RelationType.CheckConnectionRule(委任方,責任方)&lt;br /&gt;{&lt;br /&gt; &lt;span class="code-comment"&gt;//存入資料庫&lt;br /&gt;&lt;/span&gt;     }&lt;br /&gt;&lt;span class="code-keyword"&gt;break&lt;/span&gt;;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-7661942873276917417?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/7661942873276917417/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=7661942873276917417' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/7661942873276917417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/7661942873276917417'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2007/12/analysis-pattern-organization.html' title='Analysis Pattern--Organization Structures(2)'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cvihUH5Nlq8/SIV0ZrdNkOI/AAAAAAAAADk/IEUqCx7XXlY/s72-c/obj5.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-1645359906673025225</id><published>2007-11-29T22:59:00.000-08:00</published><updated>2008-07-21T22:34:19.222-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='系統分析'/><title type='text'>Analysis Pattern--Organization Structures(1)</title><content type='html'>&lt;h3 id="前言"&gt;前言 &lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt; 軟體工程的分析工作，一直是掌握專案成敗的關鍵。然而它也如同軟體開發的本質，捉摸不定，往往難以判斷某項分析的影響程度。Analysis Pattern出版超過十年，但其價值至今不減，它使用了模式的概式，介紹了數種在各種領域常用的分析手法。我們了解OO的思考，是以把真實世界的運作溶 入我們的程式。但真實世界是相當複雜的，隨興的找出物件，構築一個系統是行不通的。透過這本書，我們可以看出一些行之有年的技巧，幫助我們設計出一個易於 理解又有彈性的物件模型。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h3 id="OrganizationStructures"&gt;Organization Structures &lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt; 廢話說多了，我們來看第一種相當常見的概念，組織。 &lt;/p&gt; &lt;/blockquote&gt; &lt;h4 id="設計一"&gt;設計一 &lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt;這種設計相當直覺，記得我第一次看見有組織時就是用這種設計。反應成類別的概念，會出現三個類別。由於這相當於Dependent Mapping(POEAA 262)的概念，Division有Department的集合，Department有Persion的集合。而資料庫的設計方式會是三個Table， 一個關聯一個。 &lt;/p&gt; &lt;/blockquote&gt; &lt;div style="text-align: left;"&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SIVwsieTf8I/AAAAAAAAADE/P-2HONOSkps/s1600-h/obj1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SIVwsieTf8I/AAAAAAAAADE/P-2HONOSkps/s320/obj1.jpg" alt="" id="BLOGGER_PHOTO_ID_5225706853103796162" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt; &lt;/p&gt; &lt;h4 id="設計二"&gt;設計二 &lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; 以上的設計，隨著組織階層的擴充就行不通了，於是出現第二種常見的設計。以類別的觀點，一個具有兩個屬性，一個指著上層，一個指著下層。資料庫的設計會是一個Table，具上層組織及下層組織的欄位。 &lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cvihUH5Nlq8/SIVw4K-AP-I/AAAAAAAAADM/PbCr9VuD4Jc/s1600-h/obj2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_cvihUH5Nlq8/SIVw4K-AP-I/AAAAAAAAADM/PbCr9VuD4Jc/s320/obj2.jpg" alt="" id="BLOGGER_PHOTO_ID_5225707052952731618" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;h4 id="設計三"&gt;設計三 &lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt;一般組織的設計，是包含員工在內的。在此我們導入一個Party的觀念，來幫我們處理這種樹狀分層負責的概念。Party是不分人、組織的，它是父 類別，而人員組織是其子類別，這是OO設計的繼承觀念。關於資料庫的設計，可以參考POEAA中關於ORM繼承的設計。例如我使用Class Table Inheritance(POEAA 285)的設計，就該設計成三個Table，其中Party放共通的欄位，並產生unique Key。其他兩個Table則放其各自的欄位，並與Party共用Unique Key。 &lt;/p&gt; &lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SIVxDmW7dXI/AAAAAAAAADU/Xf3PjdaeEqM/s1600-h/obj3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SIVxDmW7dXI/AAAAAAAAADU/Xf3PjdaeEqM/s320/obj3.jpg" alt="" id="BLOGGER_PHOTO_ID_5225707249283593586" border="0" /&gt;&lt;/a&gt;&lt;h4 id="設計四"&gt;設計四&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt; 我們把上一層下一層的設計放入Party，一切看來非常合理。即使再多一種身份要參加我們的組織樹，也沒問題。 &lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cvihUH5Nlq8/SIVxO_-WVGI/AAAAAAAAADc/1yvByF3EYmI/s1600-h/obj4.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cvihUH5Nlq8/SIVxO_-WVGI/AAAAAAAAADc/1yvByF3EYmI/s320/obj4.jpg" alt="" id="BLOGGER_PHOTO_ID_5225707445138379874" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-1645359906673025225?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/1645359906673025225/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=1645359906673025225' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/1645359906673025225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/1645359906673025225'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2007/11/analysis-pattern-organization.html' title='Analysis Pattern--Organization Structures(1)'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cvihUH5Nlq8/SIVwsieTf8I/AAAAAAAAADE/P-2HONOSkps/s72-c/obj1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7430228878465597108.post-6166152174853351974</id><published>2007-10-15T07:58:00.000-07:00</published><updated>2008-06-01T18:51:14.050-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='架構'/><title type='text'>IBatis.NET的DataAccess</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;研究原因：&lt;/span&gt;&lt;br /&gt;在建立良好的中間層時，需要一些好的工具。因為中間層不外乎處理事務交易，並靈活的連接資料層。如果在不想完全手工設計，可能就得依賴一些framework。.NET的世界，有Sprint.NET、Windsor、StructureMap等IOC的framework，都可以做這部分的事務。但我以為如果不想動用到IOC，IBatis.NET的DataAccess是種簡易又好用的工具。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;工具說明：&lt;/span&gt;&lt;br /&gt;IBatis.NET是套半手工的ORM，或許不能叫ORM。它既不產生SQL，也不提供新的語法來產生SQL。它就是要讓你自己寫SQL，做出物件與資料庫的對應。其中DataMapper負責對應，DataAccess則是負責管理資料層的呼叫，並統一交易的呼叫方式，這正是我要它的一個功能。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;使用方法：&lt;/span&gt;&lt;br /&gt;&lt;p&gt; 這是我的系統架構： &lt;/p&gt; &lt;ol&gt;&lt;li&gt;TestIBatisNet：是網頁專案 &lt;/li&gt;&lt;li&gt;Service：是系統的邊界層，也負責Transaction的開關。 &lt;/li&gt;&lt;li&gt;Domain：是主要的商業邏輯元件 &lt;/li&gt;&lt;li&gt;IDao：是Dao的界面 &lt;/li&gt;&lt;li&gt;SQLServerDao：負責連接SQLServer資料庫的Dao。 &lt;/li&gt;&lt;li&gt;AccessDao：負責連接Access資料庫的Dao。&lt;/li&gt;&lt;/ol&gt;這是我用的一貫架構，我相信它足以應付各式專案。當然表現層的還沒有仔細分類，因為還沒決定何種framework。而這次我就單用DataAccess來處理中間層的一些問題。&lt;br /&gt;&lt;h3 id="設定"&gt;&lt;span style="font-size:100%;"&gt;設定 &lt;/span&gt;&lt;/h3&gt; &lt;p&gt; 僅使用DataAcess的，有兩個需設定，dao.Config及providers.config。&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;daoConfig&lt;br /&gt;xmlns="http://ibatis.apache.org/dataAccess"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;providers resource="Config/providers.config"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;context id="SqlServerDao" default="true"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Database connection information --&amp;gt;&lt;br /&gt;&amp;lt;database&amp;gt;&lt;br /&gt;&amp;lt;provider name="sqlServer2.0"/&amp;gt;&lt;br /&gt;&amp;lt;dataSource name="ERP" connectionString="Data Source=localhost;Initial Catalog=ERP;User ID=sa;Password=12345"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/database&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;daoFactory&amp;gt;&lt;br /&gt;&amp;lt;dao interface="IDao.IDepartmentDao, IDao" implementation="SQLServerDao.DepartmentDao, SQLServerDao" /&amp;gt;&lt;br /&gt;&amp;lt;/daoFactory&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/context&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;context id="AccessDao" default="false"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Database connection information --&amp;gt;&lt;br /&gt;&amp;lt;database&amp;gt;&lt;br /&gt;&amp;lt;provider name="OleDb2.0"/&amp;gt;&lt;br /&gt;&amp;lt;dataSource name="ERP" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data   Source=D:\Projects\TestIBaitsNet\ExternalBin\ERP.mdb"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/database&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;daoFactory&amp;gt;&lt;br /&gt;&amp;lt;dao interface="IDao.IDepartmentDao, IDao" implementation="AccessDao.DepartmentDao, AccessDao" /&amp;gt;&lt;br /&gt;&amp;lt;/daoFactory&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/context&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/daoConfig&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;/blockquote&gt; &lt;p&gt; 上面指出有兩種Context，系統可在運行時自由切換不同的Dao。daoFactory則指出，Dao介面與實作的應對關系。 &lt;/p&gt; &lt;h3 id="Dao的寫法"&gt;&lt;span style="font-size:100%;"&gt;Dao的寫法 &lt;/span&gt;&lt;/h3&gt; &lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public class DepartmentDao : IBatisNet.DataAccess.Interfaces.IDao,   IDepartmentDao&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;public Department GetDepartment(int deptID)&lt;br /&gt;{&lt;br /&gt;IDaoManager daoManager = DaoManager.GetInstance(this);&lt;br /&gt;daoSession = daoManager.LocalDaoSession as DaoSession;&lt;br /&gt;&lt;br /&gt;  IDbCommand cmd = daoSession.CreateCommand(CommandType.Text);&lt;br /&gt;&lt;br /&gt;cmd.CommandText = GetDepartment_SQL;&lt;br /&gt;IDataParameter para1 = daoSession.CreateDataParameter();&lt;br /&gt;para1.ParameterName = "@deptID";&lt;br /&gt;para1.DbType = DbType.Int32;&lt;br /&gt;para1.Value = deptID;&lt;br /&gt;&lt;br /&gt;cmd.Parameters.Add(para1);&lt;br /&gt;&lt;br /&gt;IDbDataAdapter adapter = daoSession.CreateDataAdapter(cmd);&lt;br /&gt;DataSet retDs = new DataSet();&lt;br /&gt;&lt;br /&gt;adapter.Fill(retDs);&lt;br /&gt;&lt;br /&gt;//填充物件&lt;br /&gt;return genObject(retDs);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt; 參考加入DataAccess.dll後，就可以使用DaoManager，取出目前在作用的daoManager，以及目前在處理中 daoSession。使用類似ADO.NET的方式，但背後如何開啟連接，以及DataProvider的選擇，都由DataAccess幫我們處理 了。 &lt;/p&gt; &lt;h3 id="讀入設定檔"&gt;&lt;span style="font-size:100%;"&gt;讀入設定檔 &lt;/span&gt;&lt;/h3&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;DomDaoManagerBuilder builder = new DomDaoManagerBuilder();&lt;br /&gt;builder.Configure(@"Config\dao.config");&lt;br /&gt;&lt;br /&gt;_daoManager = DaoManager.GetInstance();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt; 選擇在Service中，讀入設定檔，而且將產生的DaoManager放入靜態變數中。 &lt;/p&gt; &lt;h3 id="使用"&gt;&lt;span style="font-size:100%;"&gt;使用&lt;/span&gt;&lt;br /&gt;&lt;/h3&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;DepartmentService newService = new DepartmentService();&lt;br /&gt;Department retObj = newService.GetDepartment(int.Parse(txtDeptID.Text));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt; Web端只知道Service端的介面，以及Domain的物件。對資料的來源完全不知道。&lt;br /&gt;&lt;/p&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public Department GetDepartment(int deptID)&lt;br /&gt;{&lt;br /&gt;IDepartmentDao dao = (IDepartmentDao)_daoManager.GetDao(typeof(IDepartmentDao));&lt;br /&gt;return dao.GetDepartment(deptID);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt; Service端也不知在呼叫哪個Dao，一切是DaoAccess在決定&lt;br /&gt;&lt;/p&gt;&lt;pre style="background-color: lightgrey;"&gt;&lt;code&gt;public void InsertDepartment(Department insObj)&lt;br /&gt;{&lt;br /&gt;IDepartmentDao dao = (IDepartmentDao)_daoManager.GetDao(typeof(IDepartmentDao));&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;     _daoManager.BeginTransaction();&lt;br /&gt;      dao.InsertDepartment(insObj);&lt;br /&gt;      _daoManager.CommitTransaction();&lt;br /&gt; }&lt;br /&gt; catch (Exception ex)&lt;br /&gt; {&lt;br /&gt;      _daoManager.RollBackTransaction();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt; 我們把Transaction的開啟關閉引到呼叫物件前使用，DataAccess會幫我們處理把所有的物件包在一個Transaction中。 &lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;結論：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;小工具也可以有大功用，DataAccess解決了最基本的交易如何開啟，以及讓DAO的實現方式可以自由變動，光這兩點就不錯了。&lt;br /&gt;&lt;/p&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7430228878465597108-6166152174853351974?l=marscommentary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marscommentary.blogspot.com/feeds/6166152174853351974/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7430228878465597108&amp;postID=6166152174853351974' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6166152174853351974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7430228878465597108/posts/default/6166152174853351974'/><link rel='alternate' type='text/html' href='http://marscommentary.blogspot.com/2007/10/ibaitsnetdataaccess.html' title='IBatis.NET的DataAccess'/><author><name>Hugo</name><uri>http://www.blogger.com/profile/02669883172223147098</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
