1. 程式人生 > >設計模式怎麼使用,如何選擇設計模式

設計模式怎麼使用,如何選擇設計模式

設計模式的程式沒有一個統一的定義,都是開發人員在開發當中不斷積累,總結出來的一種可以複製重用的方案。 •    設計模式是對程式設計人員經常遇到的設計問題的可再現的解決方案 •    設計模式建立了一系列描述如何完成軟體開發領域中特定任務的規則 •    設計模式關注與複用可重複出現的結構設計方案 •    設計模式提出了一個發生在特定設計環境中的可重複出現的設計問題,並提供解決方案 •    設計模式識別並確定類和例項層次上或元件層次上的抽象關係 總結:設計模式在設計者是一種流行的思考設計問題的方法,是一套被反覆使用,多數人知曉的,經過分類編目的,程式碼設計經驗的總結。 使用了設計模式,是為了使程式碼具有可重用性,讓程式碼更容易被他人理解和保證程式碼的可靠性。
1.尋找合適的物件-->決定物件的粒度-->指定物件的介面-->描述物件的實現 尋找合適的物件 面向物件的程式由物件組成,物件包括資料和對資料進行操作的過程,物件在收到客戶的請求之後會執行相應的操作。客戶請求是使物件執行操作的唯一辦法,操作又是物件改變的內部資料的唯一方法,最困難的就是將系統分解為物件集合,要考慮許多元素:封裝、粒度、依賴關係、靈活性、效能、演化、複用等,這些都影響著系統的分解,並且一般時候這些元素還是互相沖突。 設計的許多物件來源於現實世界的分析模型,但是設計結果所得到的類通常在現實世界是不存在的,如果嚴格的反映當前世界的模型並不能產生也能反應將來世界的系統,所以設計中的抽象對於產生靈活的設計至關重要。 設計模式幫你確定並不明顯的抽象和描述這些抽象的物件,這些物件在分析階段甚至在設計階段的早期都不存在,後來為了使設計更靈活才將它們創建出來。 決定物件的粒度
物件在大小和數目上變化極大,它們能表示下到硬體上到整個應用的任何事物,怎樣決定一個物件是什麼,這是一個非常麻煩的問題,首先每個人看待問題的視角不同對問題的理解不同,所以細分問題的大小不同導致物件的粒度沒有一個明確的規定,但是設計面向物件的初衷不會變,設計面向物件的目的不會變,所以能夠達到這個目的並解決問題的是設計模式,這些模式是如何對待物件粒度本省就是一個很好的參考,一些設計模式會描述如何支援大量的最小粒度、描述將一個物件分解為許多小物件等等。 指定物件的介面 物件操作所定義的所有操作型構的集合被稱為介面,該介面描述了該物件所能接受的全部請求,任何匹配物件介面中型構的請求都可以傳送給該物件。 型別是用來標識特定介面的一個名字,如果一個物件接受某個介面所定義的所有操作請求,就可以認為該物件具有這個型別,介面可以包含其他介面作為子集,當一個型別的介面包含另外一個型別的介面時,我們就說它是另一個型別的子型別。當給物件傳送請求時,所引起的具體操作與請求本身和接受的物件有關,支援相同請求的不同物件可能對請求激發的操作有不同的實現,傳送給物件的請求和它相應的操作在執行時刻的連線稱之為動態繫結,即是指傳送的請求直到執行的時刻才受你的具體實現的約束。 設計模式根據通過確定介面的主要組成部分及介面傳送的資料型別,來幫助使用者定義介面,還會告訴使用者不能包含哪些東西,同時也指定了介面之間的關係。 描述物件的實現
物件的實現是由類定義的,類指定了物件內部的資料和表示,也定義了物件能夠完成的操作。 抽象類的主要目的是為了它的子類定義公共介面,一個抽象類將把它的部分或全部操作的實現延伸到子類中。而混入類是給其他類提供可選擇的介面或功能的類,域抽象類一樣不能例項化。 類繼承與介面的比較:首先理解物件的類與物件的型別的區別很重要,一個物件的類定義了物件是怎麼實現的,但是物件的型別只與它的介面有關,不同類的物件具有相同的型別,同時物件的類和型別也是具有緊密聯絡的,因為類定義了物件所能執行的操作,也定義了物件的型別,當說一個物件是一個類的例項時,即指該物件支援類所定義的介面。然後回到繼承和介面,類繼承根據一個物件的實現定義了另外一個物件的實現,簡而言之就是程式碼和表示的共享機制,但是介面繼承描述了一個物件什麼時候可以被另外一個物件替代,很多語言不區分這兩個概念,所以容易混淆。儘管大部分設計語言不區分介面繼承和實現繼承這兩個的區別但是使用中還是分別對待它們,很多設計模式依賴於這種差別,比如說一個模式中的物件必須有一個公共型別,但一般情況下它們不具有公共的實現。 對介面程式設計,雖然類繼承允許從已存在的類中繼承所需要的絕大部分功能,就可以獲得新的實現,然和實現的複用只實現了一半,定義具有相同介面的物件族這一功能很重要,因為多型需要這種能力,只根據抽象介面程式設計有兩個好處:客戶無需知道使用物件的特定型別,只需物件有客戶所期望的型別,無須知道使用的物件是用什麼類來實現的,只須知道定義介面的抽象類。這將極大的減少子系統實現之間的相互依賴關係,也產生了可複用的看向物件的設計原則,針對介面程式設計而不是針對實現程式設計。 不將變數宣告某個特定的具體類的例項對像,而是遵從抽象類所定義的介面。 2.運用複用機制-->關聯執行時刻和編譯時刻的結構-->設計應支援變化 運用複用機制 這是重中之重,是面向物件最關鍵的地方,也是一個設計好壞的關鍵。 理解物件、介面、類和繼承之類並不難但是關鍵在於如何運用好,面向物件系統中的功能複用最常用的兩種是物件組合和類繼承。 類繼承:允許你根據其他的類實現來定義一個類的實現,這種通過生成子類的複用方式稱為白箱複用,這個白箱是相對可視性而言:在繼承中父類的內部細節對子類可見。 物件組合:更復雜的功能可以通過組裝活組合物件來獲得,物件組合要求被組合的物件具有良好的介面,這種複用風格被稱為黑箱複用:因為物件的內部細節都是不可見的。 繼承和組合都是各有優缺點的,類繼承是在編譯時刻靜態定義的且可以直接使用,因為程式設計語言直接支援類繼承,類繼承可以較方便的改變被複用的實現,但是繼承被認為是破壞了封裝性,子類的實現與他的父類有緊密的依賴關係,父類實現的任何變化必然會導致子類發生變化,無法在執行的時候進行改變從父類繼承的實現。當需要複用子類的時候,實現上的依賴就會產生一些問題,如果繼承下來的實現不適合解決新的問題則父類就會被重寫,這樣限制了靈活性並最終限制了複用性,有一個解決的方案繼承抽象類因為抽象類通常提供較少的實現。 物件組合是通過獲得其他的物件的引用而在執行時刻動態定義的,組合要求物件遵守彼此的介面約定。因為物件只通過介面訪問,只要型別一樣執行時刻還可以用一個物件來替代另外一個物件,更進一步因為對像的實現是基於介面寫的,所以實現上較少的具有依賴關係。優先使用對像組合有助於保持每個類被封裝並集中在單個任務中,基於物件組合的設計會有更多的物件而又較少的類,系統執行將依賴於對像間的關係而不是被定義在某個類中。 在理想情況下不應該為了獲得複用而去建立新的構建,應該能夠只使用對像組合技術,通過組裝已有的構件就能獲得你需要的功能,但是構件並不夠豐富所以通過繼承的複用使新的構建的建立比組裝已有構件要容易,一般繼承和物件一般一起使用。 委託是一種組合方式,使組合具有與繼承同樣的複用能力,在委託方式下有兩個物件處理一個請求,接受請求的物件將操做委託給它的代理者,這類似於子類將請求交給它的代理者,類似於子類將請求交給它的父類來處理。委託方式為了得到同樣的效果接受請求的物件將自己傳給委託者,使被委託的操作可以引用接受請求的物件。 委託與那些通過物件組合的義取得軟體靈活性的技術一樣具有不足:動態高度引數化的軟體比靜態的軟體更難於理解,委託是物件組合的特例它告訴你物件組合作為一個程式碼複用機制可以替代繼承。 還有另外一種功能複用技術是引數化型別,也就是類屬或模版。它允許你在定義一個型別的時候並不指定,該型別所用到的其他所有型別,未經指定的型別在使用時以引數形式提供,一個列表類能夠以它所包含元素的型別來進行引數化。引數化型別給我們提供了類繼承和物件組合外的第三種方式來組合面向物件系統中的行為。 這些技術存在著極大的不同,物件組合技術允許你在執行時刻改變組合的行為,但是它存在間接性,比較低效。繼承允許你提供操作的預設實現,並通過子類重定義這些操作,引數化型別允許改變類所用到的型別、但是繼承和引數化型別都不能在執行的時刻改變。 關聯執行時刻和編譯時刻的結構 一個面向物件程式執行時的結構和它的程式碼結構相差甚大,程式碼結構在編譯時刻被確定下來,由繼承關係固定的類組成。執行時刻結構是由快速變化的通訊對像網路組成。這兩個結構相互獨立。這時就要考慮聚合和相識的差別:聚合意味著一個物件擁有另外一個物件或對另外一個物件負責,一般稱一個物件包含另一個物件或者是另一個物件的一部分,聚合意味著聚合物件和其所有者具有相同的生命週期。相識意味著一個物件僅僅知道另外一個物件,也被稱為關聯或者引用,相識的物件可能請求彼此的操作,是一種比聚合要弱的關係,只表示了物件間的耦合關係。聚合和相識很容易混淆因為通常以相同的方法實現。從根本上講,是聚合還是相識是根據使用者的意圖而不是顯示的語言機制決定,在編譯時刻很難看出區別,聚合使用較少且比相識關係更持久而相識的出現的頻率很高但有時只存在一個操作期間,相識更具有動態性。 程式執行時刻結構和編譯時刻結構存在這麼大的差別,程式碼不可能揭示關於系統是如何工作的全部資訊,系統執行的時刻更多受到設計者的影響而不是程式語言, 設計應該支援變化 獲得最大限度複用的關鍵在於對新需求和已有需求發生變化時的預見性,要求系統設計能夠相應的改進,要為了完成這種設計,就必須要考慮系統的執行週期內會發生什麼變化,設計模式可以確保系統能以特定方式變化,從而幫助你避免重新設計系統,設計模式允許系統結構的某個方面的變化獨立於其他方面,設計模式在開發如下三類主要軟體的中所起的作用:應用程式、工具箱、框架。 應用程式:應該優先考慮內部複用性、可維護性、可擴充性,內部複用性不會做多餘的設計,設計模式通過減少內部依賴性來提高內部複用性,鬆散耦合也增強了一類物件與其他多個物件協作的可能性也會增強可擴充性。 工具箱:一個應用會經常使用來自一個或多個被稱為工具箱的預定義類庫的類,工具箱時一組相關的可複用的類的集合,這些類提供了通用的功能,工具箱強調的是程式碼複用,是面向物件環境下的子程式庫,只是為你的應用提供功能上的幫助。工具箱的設計要比應用程式難得多,因為要對許多應用是可用的和有效的。要避免假設和依賴就變得很重要因為不知道工具箱要用到什麼地方,會影響到效率和適用性。 框架:是構成一類特定軟體可複用設計的一組相互協作的類,可以通過定義框架抽象類的應用相關的子類從而將一個框架定製為特定的應用。它規定了應用的體系結構,定義了整體結構、類和物件的分割,各部分的主要責任,類和物件怎麼協作,控制流程。以便於使用者能夠集中精力於應用本身。這個層次的複用導致了應用和它所基於的軟體之間的反向控制,當使用工具箱時使用者寫程式主體而不是呼叫你想複用的程式碼,而使用框架的時候應該複用應用的主體,寫主體掉用程式碼,這些應用具有相似的結構,任何對框架的實質性修改都會降低框架的所帶來的好處。 因為模式和框架有些類似,它們的不同是,設計模式更加抽象並且是比框架還有小的體系結構元素,框架要比設計模式更加特例化總是針對一個特定的應用領域 3.怎樣選擇設計模式,怎樣使用設計模式 怎樣選擇設計模式 考慮設計模式怎麼結局問題,瀏覽模式的意圖部分,找出與使用者問題相關的模式,研究模式如何相互關聯,研究目的相似的的模式,考慮設計中那些是可變的,並不是考慮什麼會迫使你的設計改變而時你想要什麼變化卻又不會引起重新設計。 怎樣使用設計模式 給出一個有效應用設計模式的的循序漸進的方法 大致瀏覽一遍模式要特別注意適用性部分和效果部分以確定適合你的問題 研究結構部分、參與者部分和協作部分確保類和物件是如何關聯的 選擇模式參與者的名字,使它們在上下文中有意義,設計模式的名字通常過於抽象而不會直接出現在應用裡但是會幫助使用者哉實現中更顯示的體現出模式來。