[Head First設計模式]山西面館中的設計模式——裝飾者模式html
[Head First設計模式]山西面館中的設計模式——觀察者模式編程
[Head First設計模式]山西面館中的設計模式——建造者模式設計模式
[Head First設計模式]餃子館(冬至)中的設計模式——工廠模式安全
[Head First設計模式]一我的的平安夜——單例模式框架
[Head First設計模式]搶票中的設計模式——代理模式ide
今天忽然跟朋友談起設計原則,內心想一想面向對象的設計原則與要素都有哪些?掰掰指頭算算能說出幾個?作了這麼久開發,能有幾個能說全的?更別說在項目總去使用了。也許,一些設計原則已經成爲習慣,好比單一指責,不用說,你們都懂的。這裏也總結一下,但願之後多看多想多練。函數
一個類,只有一個引發它變化的緣由。應該只有一個職責。每個職責都是變化的一個軸線,若是一個類有一個一上的職責,這些職責就耦合在了一塊兒。這回致使脆弱的設計。當一個職責發生變化時,可能會影響其它的職責。另外,多個職責耦合在一塊兒,會影響複用性。例如:要實現邏輯和界面的分離。post
什麼是職責ui
SRP中,把職責定義爲「變化的緣由」。若是你能想到N個動機去改變一個類,那麼這個類就具備多於一個的職責。這裏說的「變化的緣由」,只有時機發生時纔有意義。可能預測到會有多個緣由引發這個類的變化,但這僅僅是預測,並無真的發生,這個類仍可看做具備單一職責,不須要分離職責。url
開放封閉原則是全部面向對象原則的核心。軟件設計自己所追求的目標就是封裝變化,下降耦合,而開放封閉原則正式對這一目標的最直接體現。其餘的設計原則,不少時候是爲實現這一目標服務的,例如以Liskov替換原則實現最佳的,正確的繼承層次,就能保證不會違反開放封閉原則。
關於開放封閉原則,其核心思想
軟件實體應該是可擴展,而不可修改的。也就是說,對擴展是開放的,而對修改是封閉的。
所以,開放封閉原則主要體如今如下兩個方面:
對擴展開放,意味着有新的需求或變化時,能夠對現有代碼進行擴展,以適應新的狀況。
對修改封閉,意味着類一旦設計完成,就能夠獨立完成其工做,而不要對類進行任何修改。
「需求老是變化的」,「世界上沒有一個軟件是一成不變的」,這些言論對軟件需求是最經典的表白。從中投射出一個關鍵的意思就是,對於軟件設計者來講,必須在不須要對原有系統進行修改的狀況下,實現靈活的系統擴展。而如何作到這一點呢?
只有依賴於抽象。實現開放封閉的核心思想就是對抽象編程,而不是對具體編程,由於抽象相對穩定。讓類依賴於固定的抽象,因此對修改就是封閉的;而經過面向對象的繼承和多態機制,能夠實現對抽象體的繼承,經過覆寫其方法來改變固有行爲,實現新的擴展方法,因此對於擴展是開放的。這是實施開放封閉原則的基本思路,同是這種機制是創建在兩個基本的設計原則的基礎上,這就是Liskov替換原則和合成/聚合複用原則。
對於違反這一原則的類,必須進行重構來改善,經常使用於實現的設計模式主要有Template Method模式和Strategy模式。而封裝變化是實現這一原則的重要手段,將常常發生變化的狀態封裝爲一個類。
其核心思想就是:子類必須可以替換其基類。這一思想體現爲對繼承機制的約束規範,只有子類可以替換基類時,才能保證系統在運行期內識別子類,這是保證繼承複用的基礎。在父類和子類的具體行爲中,必須嚴格把握繼承層次中的關係和特徵,將基類替換爲子類,程序的行爲不會發生任何變化。同時,這一約束反過來則是不成立的,子類能夠替換基類,可是基類不必定能替換子類。
Liskov替換原則,主要着眼於對抽象和多態創建在繼承的基礎上,所以只有遵循Liskov替換原則,才能保證繼承複用是可靠的。實現的方法是面向接口編程:將公共部分抽象爲基類接口或抽象類,經過繼承抽象類或實現接口,在子類中經過覆寫父類的方法實現新的方式支持一樣的職責。
Liskov替換原則是關於繼承機制的設計原則,違反了Liskov替換原則就必然致使違反開放封閉原則。
Liskov替換原則可以保證系統具備良好的拓展性,同是實現基於多態的抽象機制,可以減小代碼冗餘,避免運行期的類型判別。
所謂依賴倒置原則(Dependence Inversion Principle)就是要依賴於抽象,不要依賴於具體。簡單的說就是要求對抽象進行編程,不要對實現進行編程,這樣就下降了客戶與實現模塊間的耦合。
面向過程的開發,上層調用下層,上層依賴於下層,當下層劇烈變更時上層也要跟着變更,這就會致使模塊的複用性下降並且大大提升了開發的成本。 面向對象的開發很好的解決了這個問題,通常狀況下抽象的變化機率很小,讓用戶程序依賴於抽象,實現的細節也依賴於抽象。即便實現細節不斷變更,只要抽象不變,客戶程序就不須要變化。這大大下降了客戶程序與實現細節的耦合度。
一個應用中的重要策略決定及業務模型正是在這些高層的模塊中。也正是這些模型包含着應用的特性。可是,當這些模塊依賴於低層模塊時,低層模塊的修改將會直接影響到它們,迫使它們也去改變。這種境況是荒謬的。應該是處於高
層的模塊去迫使那些低層的模塊發生改變。應該是處於高層的模塊優先於低層的模塊。不管如何高層的模塊也不該依賴於低層的模塊。並且,咱們想可以複用的是高層的模塊。經過子程序庫的形式,咱們已經能夠很好地複用低層的模塊了。當高層的模塊依賴於低層的模塊時,這些高層模塊就很難在不一樣的環境中複用。可是,當那些高層模塊獨立於低層模塊時,它們就能很簡單地被複用了。這正是位於框架設計的最核心之處的原則。
依賴倒置原則
A.高層次的模塊不該該依賴於低層次的模塊,他們都應該依賴於抽象。
B.抽象不該該依賴於具體,具體應該依賴於抽象。
使用多個專門的接口比使用單一的總接口要好。
一個類對另一個類的依賴性應當是創建在最小的接口上的。
一個接口表明一個角色,不該當將不一樣的角色都交給一個接口。沒有關係的接口合併在一塊兒,造成一個臃腫的大接口,這是對角色和接口的污染。
「不該該強迫客戶依賴於它們不用的方法。接口屬於客戶,不屬於它所在的類層次結構。」這個說得很明白了,再通俗點說,不要強迫客戶使用它們不用的方法,若是強迫用戶使用它們不使用的方法,那麼這些客戶就會面臨因爲這些不使用的方法的改變所帶來的改變。
分離的手段主要有如下兩種:
一、委託分離,經過增長一個新的類型來委託客戶的請求,隔離客戶和接口的直接依賴,可是會增長系統的開銷。
二、多重繼承分離,經過接口多繼承來實現客戶的需求,這種方式是較好的。
面向對象的三個基本特徵是:封裝、繼承、多態。
封裝
隱藏對象的屬性和實現細節,僅對外公開接口,控制在程序中屬性的讀取和修改的訪問級別。
封裝途徑
封裝就是將抽象獲得的數據和行爲(或功能)相結合,造成一個有機的總體,也就是將數據與操做數據的源代碼進行有機的結合,造成「類」,其中數據和函數都是類的成員。
封裝的目的是加強安全性和簡化編程,使用者沒必要了解具體的實現細節,而只是要經過外部接口,以特定的訪問權限來使用類的成員。
封裝是實現面向對象程序設計的第一步,封裝就是將數據或函數等集合在一個個的單元中(咱們稱之爲類)。被封裝的對象一般被稱爲抽象數據類型。
封裝的意義:
封裝的意義在於保護或者防止代碼(數據)被咱們無心中破壞。在面向對象程序設計中數據被看做是一箇中心的元素而且和使用它的函數結合的很密切,從而保護它不被其它的函數意外的修改。
封裝提供了一個有效的途徑來保護數據不被意外的破壞。相比咱們將數據(用域來實現)在程序中定義爲公用的(public)咱們將它們(fields)定義爲私有的(private)在不少方面會更好。私有的數據能夠用兩種方式來間接的控制。第一種方法,咱們使用傳統的存、取方法。第二種方法咱們用屬性(property)。
使用屬性不只能夠控制存取數據的合法性,同時也提供了「讀寫」、「只讀」、「只寫」靈活的操做方法。
訪問修飾符:
private:只有類自己能存取.
protected:類和派生類能夠存取.
internal:只有同一個項目中的類能夠存取.
protected Internal:是Protected和Internal的結合.
public:徹底公開.
繼承
繼承主要實現重用代碼,節省開發時間。
1、C#中的繼承符合下列規則:
2、new關鍵字
若是父類中聲明瞭一個沒有friend修飾的protected或public方法,子類中也聲明瞭同名的方法。則用new能夠隱藏父類中的方法。(不建議使用)
3、base關鍵字
base 關鍵字用於從派生類中訪問基類的成員:
多態
1、多態:同一操做做用於不一樣的對象,能夠有不一樣的解釋,產生不一樣的執行結果。在運行時,能夠經過指向基類的指針,來調用實現派生類中的方法。
編譯時的多態性:
編譯時的多態性是經過重載來實現的。對於非虛的成員來講,系統在編譯時,根據傳遞的參數、返回的類型等信息決定實現何種操做。
運行時的多態性:
運行時的多態性就是指直到系統運行時,才根據實際狀況決定實現何種操做。C#中,運行時的多態性經過虛成員實現。
編譯時的多態性爲咱們提供了運行速度快的特色,而運行時的多態性則帶來了高度靈活和抽象的特色。
2、實現多態:
3、override關鍵字:
重寫父類中的virtual修飾的方法,實現多態。
參考:
設計原則:百度百科,Head First設計模式
三特徵:http://www.cnblogs.com/mountain-mist/articles/1214996.html
這裏雖然很基礎的東西,在總結的過程當中,一直在思考,本身在項目有沒有違反哪一原則?不斷思考+不斷重構+不斷摸索=成長。從網上搜集了一部分,記錄在此,方便回顧。