所以有很多方法來構建對象(我在這裏談論OOP)。對於這個問題,我將使用經典的「汽車」OOP示例。基本上,當兩個程序結構都能達到目標時,我怎麼知道什麼時候把汽車變成一個物體,或者汽車的車輪是什麼物體?如何設計對象?
如何對對象的各個部分進行分類和分類,以確定它們是否更適合作爲對象的簡單屬性或變量,或者它們是否真的需要自己成爲對象?
所以有很多方法來構建對象(我在這裏談論OOP)。對於這個問題,我將使用經典的「汽車」OOP示例。基本上,當兩個程序結構都能達到目標時,我怎麼知道什麼時候把汽車變成一個物體,或者汽車的車輪是什麼物體?如何設計對象?
如何對對象的各個部分進行分類和分類,以確定它們是否更適合作爲對象的簡單屬性或變量,或者它們是否真的需要自己成爲對象?
好你的第一件事情要實現的是OOAD(「面向對象的分析和設計」)是一種工具而不是達到目的的手段。你從這個過程中得到的是一個模型,而不是你正在建模的真實表示。該模型做出了某些假設。該模型的目的是解決您的問題。
那麼你怎麼知道如何設計對象呢?你怎麼知道你是否做得對?最終的結果:它解決了你的問題?
因此,對於汽車的例子,在某些車型中,汽車數量可能只是一個整數,例如通過交通模型中的交叉口的汽車交通量。在這樣的模型中,你很少關心汽車的製造,型號或結構,只是數量。 (例如)你可能會關心車輛的類型。您是否將該車型作爲車型或車型的車輛對象進行建模?或者只是分開carCount和truckCount符合?
簡短的回答是:以最合適的爲準。
作爲對象或不是對象的正常測試是否有行爲?請記住,最終對象=數據+行爲。
所以,你可能會說,汽車有以下狀態:
你可能只會關心一小部分:選擇任何相關的東西。賽車遊戲可能會更詳細地介紹車輪,例如車輪的熱度,磨損程度,寬度和胎面類型等。在這種情況下,車輪物體可以說是所有這種狀態的集合(但行爲很少),因爲汽車有許多車輪和車輪可以互換。
因此,提出了關於對象的第二點:由於關係,對象可以存在,因此對象表示一組完整的數據。所以輪子可以有踏面,寬度,溫度等等。你不能把它分開,並說汽車有胎面但沒有車輪寬度,所以輪子作爲一個物體是合理的,因爲輪子是完全可以互換的。
但是,這又有什麼意義呢?這是關鍵問題。
不要從分類東西開始 - 人們似乎太渴望開始構建繼承層次結構。
寫下具體的具體場景列表 - 你的應用程序將一步一步做什麼。一個對象模型只有在你需要它做什麼時纔有用 - 所以從這些場景開始回顧一下,看看你可以擺脫哪一個共同的對象和行爲。
確定場景中的「角色」 - 不一定是實際的類名稱 - 只是在通過具體場景思考軟件如何工作時出現的模糊「角色」。這些角色後來可能成爲類,接口,抽象類 - 無論您需要什麼 - 一開始他們只是做一種工作的佔位符。
確定每個角色「做」什麼。關鍵是擁有一大堆命名角色 - 用於識別對象將執行的操作。 Thins是關於提煉出每個角色可以做的一系列事情 - 他們可能會做所有事情,或者組合一堆其他對象來完成這項工作,或者他們可能會協調工作......這取決於您的場景。
OOD/OOP中最重要的事情就是對象做事 - 不是他們內部 - 他們做什麼。
早在就不要考慮繼承問題 - 因爲它會將你綁定在過於複雜的層次結構中,並使你在面向SQL的編程而不是面向對象編程方面進行思考。繼承只是共享通用代碼的一種方式。有很多其他的方式 - 委託,混入,基於原型的編程...
這裏有一些指引,我想出了幫助這樣的:
What should be on a checklist that would help someone develop good OO software?
屬性或變量通常是一種語言的「基礎」類型。問題是你可以合理地抽象。
例如,可以減少一個Wheel
於由基類型,如整數,浮點值和字符串的描述符,其表示任何車輪的特徵屬性:diameter
width
recommendedPressure
numberOfTreads
,,,,brand
。這些屬性都可以用基本類型表示,以生成Wheel
對象。
您可以將其中一些屬性分組爲一個更抽象的排列,您可以重複使用,而不受Wheel
的限制?我想是這樣。也許創建一個Dimensions
對象,其屬性爲diameter
和width
。然後,您的Wheel
有一個Dimensions
對象實例與其關聯,而不是diameter
和width
。但是,您可以考慮將該Dimensions
對象與其他對象一起使用,而其他對象可能不一定是Wheel
實例。
回到列表中,您可以減少Car
由基本類型組成,但也可以將其他對象(例如Wheel
對象)組成。這樣做是明智的,因爲其他電機和非機動車輛(例如Bicycle
)也包含Wheel
實例。
摘要Wheel
和Dimensions
允許您在最初可能不考慮的不同上下文中重用這些對象類型。從理論上講,它讓你的生活變得更輕鬆,因爲你的代碼重寫的次數更少。
如果您可以創建對象的層次結構,那麼最深的最底層對象只由幾個基本類型組成,這可能是一個很好的開始。
如果「兩個程序結構都能完成目標」的確如此,那麼選擇哪個並不重要。
但是,如果程序沒有一個固定的「目標」,但會在其整個生命週期內發生顯着變化,那麼現在就選擇一個,然後根據未來修改的需要進行重構。我們稱之爲「軟件」是有原因的。
我喜歡Wirfs-Brock的Responsibility-Driven Design (RDD),並且還推薦Alistair Cockburn更新(免費論文)Responsibility-Driven Modeling方法。
在超過15年的面向對象開發過程中,每當我感覺自己迷失在軟件架構中時,回到RDD基礎總是會幫助我澄清軟件應該做什麼以及如何做。
如果您喜歡測試驅動的方法,this article顯示瞭如何將RDD與嘲諷對象和測試聯繫起來。
耶!我也是。 RDD是對我所從事的項目做出最大差異的一件事。 (好吧,當然,他們都是測試驅動的項目 - 但RDD具有減少複雜性和消除面嚮對象語言的Pascal程序員思考的潛力。) – daf 2009-11-23 04:39:43
這裏有一些很好的答案,但可能比你想要的要多。簡單談談您的具體問題:
我怎麼知道什麼時候做汽車的物體,或汽車的車輪的對象,當兩個程序結構將實現目標?
當你需要區分一個實例和另一個實例時,你需要一個對象。對象的關鍵區別是:它具有身份。
將此答案略微擴展到類,當兩個相似對象的行爲和/或屬性發生分歧時,您需要一個新類。
因此,如果您正在建模計算車輪的交通模擬,則具有NumberOfWheels屬性的Vehicle類可能就足夠了。如果您使用詳細的路面和車輪扭矩物理模擬賽車模擬,則每個車輪可能都需要是獨立的物體。
如何對對象的各個部分進行分類和分類,以確定它們是否更適合作爲對象的簡單屬性或變量,或者它們是否真的需要自己成爲對象?
關鍵的區別是身份和行爲。具有獨特存在的部分是一個對象。具有自主行爲的部分需要自己的類。例如,如果您要創建一個非常簡單的汽車碰撞模擬,則NumberOfPassengers和DamageResistance可能是通用Vehicle類的充足屬性。這足以告訴你汽車是否合計並且乘客倖存下來。如果您的模擬更加詳細,也許您想知道每位乘客在正面碰撞中撞得多遠,那麼您需要在每輛車上安裝一個Passenger類和不同的Passenger對象。
成長你的類自下而上。
1)類邊界和語義取決於上下文。在你有上下文之前,你什麼都沒有。 (你的例子中甚至可能沒有汽車)。上下文由用戶故事(或用例)給出。
2)將給定上下文建議的所有狀態和行爲放到一個類中(如果需要,可以在用戶故事後面命名)。
3)使用系統Refactoring將這個類分成不同的類。重構時,使用現有的類作爲重用機會。
完成後,您將擁有一組定義良好的類,它們足以滿足給定用戶故事(以及之前出現的用戶故事)的需求。
+1非常好的回答:) – 2009-11-23 04:01:06