- 如果想成為一名更優秀的軟件設計師, 了解優秀軟件設計的演變過程比學習優秀的設計本身更有價值, 因為設計的演變過程蘊藏大智. <<重構與模式>>
- 重要的不是你將來會不會用到這些設計模式, 而是通過這些模式讓你找到”封轉變化”, “對象間松散耦合”, “針對接口編程”的感覺, 從而設計出更易維護, 易擴展, 易復用, 靈活性好的程.
- 聚合關系(Aggregation): 表示一種弱的”擁有”關系, 體現的是A對象可以包含B對象, 但B對象不屬于A組合的一部分(如雁和雁群).
- 組合關系(Composition): 表示一種強的”擁有”關系, 體現了嚴格的部分與整體的關系, 部分和整體的生命周期一. (鳥和翅膀)
- 當你發現你已經可以掌握次程序語言之后, 你可以選擇:
向上延伸: 學習面向對象設計, 設計模式, 反射以及軟件工. 讓自己具備做大型項目的能.
2. 向下延伸: 深入了解語言的內部運行機制, 例如數據結構, 操作系統的原理, 計算機組成與結.
3. 向旁延伸: 學習不同應用領域的API, 例如: 多媒體, 數據庫, 分布式運.
## JAVA變量的種類:
```java
Class MyClass{
static int a;
int b ;
public static void myMethod(int c){
try{
int d;
}catch(Exception e){}
}
public MyClass(int f){
int[] g = new int[10];
}
```
類變量: 聲明在類內, 方法之外, 且使用了static修飾的變例如變量.
成員變量: 聲明在類內, 方法之外, 且未使用static修飾的變量, 如變量.
方法參數: 聲明在方法的小括號內的變量, 如變量.
狹義的局部變量: 聲明在方法內的變量, 如變量d,異常處理參數: 聲明在catch小括號內的變量, 如變量.
構造方法參數: 聲明在構造方法的小括號內的變量, 如變量.
數組元素: 數組的元素沒有識別名稱, 必須透過數組和索引來組織, 如變量g[0].
類與類之間的關系:
1)關聯(Association)關系:表示一個類‘知道’另一個類。比如,企鵝和氣候之間的關系。關聯關系用實線箭頭表示。
2)聚合(Aggregation)關系:表示一種弱的‘擁有’關系,體現的是A對象可以包含B對象,但B對象不是A對象的一部分。比如,雁群和大雁的關系。聚合關系用空心的菱形+實線箭頭來表示。
3)組合(Composition)關系:表示一種強的‘擁有’關系,體現了嚴格的部分和整體的關系,部分和整體的生命周期一樣。比如,鳥和其翅膀就是組合關系。組合關系用實心的菱形+實線箭頭來表示。
4)依賴(Dependency)關系:比如動物要有生命,需要有氧氣,水和食物。那么,動物依賴于氧氣,水和食物類。依賴關系用虛線箭頭來表示。
格言:編程是一門技術,更加是一門藝術,不能只滿足于寫完代碼運行結果正確就完事,要時常考慮如何讓代碼更加簡練,更加容易維護,容易擴展和復用,只有這樣才可以真正得到提高,寫出優雅的代碼真的是一件很爽的事情!
面向對象的編程,并不是類越多越好,類的劃分是為了封裝,但分類的基礎是抽象,具有相同屬性和功能的抽象集合才是類。
策略模式(Strategy):它定義了算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化,不會影響到使用算法的客戶。
策略模式是一種定義一系列算法的方法,從概念上看,所有這些算法完成的都是相同的工作,只是實現不同,它可以以不同的方式調用所有的算法,減少各種算法類與使用算法類之間的耦合。
優點:1)策略模式的Strategy類層次為Context定義了一系列的可供重用的算法或行為。繼承有助于析取出這些算法中的公共功能。
2)簡化了單元測試,因為每個算法都有自己的類,可以通過自己的借口單獨測試。
3)策略模式封裝了變化。
策略模式就是用來封裝算法的,但在實踐中,我們發現可以用它來封裝幾乎任何類型的規則,只要在分析過程中聽到需要在不同時間應用不同的業務規則,就可以考慮使用策略模式處理這種變化的可能性。
單一職責原則:就一個類而言,應該僅有一個引起它變化的原因。
如果一個類承擔的職責過多,就等于把這些職責耦合在一起,一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到意想不到的破壞。比如哦羅斯方塊的上下左右控制職責。
軟件設計真正要做的許多內容,就是發現職責并把那些職責相互分離。其實要去判斷是否應該分離出類來,也不難,那就是:如果你能夠想到多于一個的動機去改變一個類,那么這個類就具有多于一個的職責,此時,就應該考慮類的職責分離。
開放-封閉原則:就是說軟件實體(類,模塊,方法等)應該可以擴展,但是不可修改。
這個原則其實是有兩個特征,一個是:對于擴展是開放的(open for extension),另一個是:對于更改是封閉的(closed for modification).
面對需求,對程序的改動是通過增加新代碼進行的,而不是更改現有的代碼。這是‘開放-關閉原則’的精神所在。
組合聚合復用原則;
開放-封閉原則是面向對象設計的核心所在。
依賴倒轉原則:
1)高層模塊不應該依賴于底層模塊。兩個都應該依賴抽象。
2)抽象不應該依賴細節。細節因該依賴抽象。
(針對接口編程,不要對實現編程)
1)迪米特法則(LoD):如果兩個類不必彼此直接通信,那么這兩個類就不應當發生直接的相互作用。如果其中一個類需要調用另一個類的某一個方法的 話, 可以通過第三者轉發這個調用。
里氏代換原則:子類型必須能夠替換掉它們的父類型。(子類型一定要可以以父類型的身份出現)
M依賴倒轉其實可以說是面向對象設計的標志,用哪種語言來編寫程序不重要,如果編寫時考慮的都是針對抽象而不是針對細節編程,即程序中的所有依賴 關系都是終止于抽象類或者接口,那就是面向對象的設計,反之那就是過程化的設計了。
--->N裝飾模式:動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生產子類更為靈活。
—>代理模式(Proxy):為其他對象提供一種代理以控制對這個對象的訪問
應用場合有:
1)遠處代理,也就是為一個對象在不同的地址空間提供局部代表;
2)虛擬代理,是根據需要創建開銷很大的對象,通過它來存放實例化需要很長時間的真實對象;
3)安全代理,用來控制真實對象訪問時的權限;
4)職能指引,是指當調用真實的對象時,代理處理另外一些事;
—>P 工廠方法模式(Factory Method):定義一個用于創建對象的接口,讓子類決定實例化哪一個,工廠方法使一個類的實例化延遲到其子類。
—>Q 原型模式(prototype):就是從一個對象再建一個可定制的對象,而且不需知道任何創建的細節。(clone())
—>R 模板方法模式:定義一個操作中的算法骨架,而將一些不走延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定不走。
當不變的和可變的行為在方法的子類實現中混合在一起的時候,不變的行為就會在子類中重復出現。我們通過模板方法模式把這些行為搬移到單一的地方,這樣就幫助子類擺脫重復的不變行為的糾纏。
1)迪米特法則(LoD):如果兩個類不必彼此直接通信,那么這兩個類就不應當發生直接的相互作用。如果其中一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個調用。
—>外觀模式(Facade):為子系統中的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
—>建造者模式(Builder):將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
1)使用了建造者模式,那么用戶就只需指定需要建造的類型就可以得到它們,而具體建造的過程和細節就不需要知道了。
使用場合:建造者模式主要用于創建一些復雜的對象,這些對象內部構建間的建造順序通常是穩定的,但對象內部的構建通常面臨著復雜的變化。
觀察者模式:
2)定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。(Observer:抽象觀察者,Subject:通知者)
3)將一個系統分割成一系列相互協作的類有一個很不好的副作用,那就是需要維護相關對象間的一致性。我們不希望為了維護一致性而使各類緊密耦合,這樣會給維護、擴展和重用都帶來不便。
1)當一個對象的改變需要同時改變其他對象,而且它不知道具體有多少對象有待改變時,應該考慮使用觀察者模式。
2)一個抽象模型有兩方面,其中一方面依賴于另一方面,這時用觀察者模式可以將這兩者封裝在獨立的對象中使它們各自的變化都不會影響另一邊的變化。
菜鳥程序員碰到問題,只會用時間來擺平。
—>抽象工廠模式(Abstract Factory):提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們的具體的類。
1)IFactory是一個抽象工廠接口,它里面應該包括所有的產品創建的抽象方法。而ConcreteFactory1 \ConcreteFactory2就是具體的工廠了。
2)通常是在運行時刻再創建一個ConcreteFactory類的實例,這個具體的工廠再創建具有特定實現的產品對象,也就是說,為創建不同的產品對象,客戶端應使用不同的具體工廠。
3)抽象工廠模式最大的好處便是易于交換產品系列,由于是具體的工廠類,在一個應用中只需要在初始化的時候出現一次,這就使得改變一個應用的具體工廠變得非常容易,它只需要改變具體工廠即可使用不同的產品配置。
編程是一門藝術,這樣大批量的改動,顯然是非常丑陋的做法。
4)應用反射+抽象工廠模式來解決數據庫訪問時的可維護、可擴展的問題。
5)所有在用簡單工廠模式的地方,都可以考慮用反射技術來去除switch 或 if,解除分支判斷帶來的耦合。
switch ,if是程序里的好東西,但在應對變化上,卻顯得老態龍鐘。反射技術的確可以很好地解決它們難以應付變化,難以維護和擴展的詬病。
一個程序員如果沒有熬夜寫程序的經歷,不能算是一個好程序員,因為他沒有癡迷過,所以他不會有大成就。
面向對象其實就是希望做到代碼的責任分解。
狀態模式(State):當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像改變了其類。
--->狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過于復雜時的情況,把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把復雜的判斷邏輯簡化。當然,如果這個判斷很簡單,那就沒有必要用“狀態模式”了。
2)狀態模式的好處是將與特定狀態相關的行為局部化,并且將不同狀態的行為分割開來。
3)將特定的狀態相關的行為都放入一個對象中,由于所有與狀態相關的代碼都存在于某個ConcreteState中,所以通過定義新的子類可以很容易地增加新的狀態和轉換。
4)使用狀態模式是為了消除龐大的條件分支語句,大的分支判斷會使得它們難以修改和擴展,就像我們最早說的刻板印刷一樣,任何變動和變化都是致命的。狀態模式通過把各種狀態轉移邏輯分布到State的子類之間,來減少相互間的依賴。
5)當一個對象的行為取決于它的狀態,并且它必須在運行時刻根據狀態改變它的行為時,就可以考慮使用狀態模式了。P189
--->適配器模式(Adapter):將一個類的接口轉換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不兼容而不能一起工作。
1)系統的數據和行為都正確,但接口不符時,我們應該考慮用適配器,目的是使控制范圍之外的一個原有對象與某個接口匹配,適配器模式主要應用于希望復用一些現存的類,但是接口又與復用環境要求不一致的情況。(主要是對象適配器模式 )
2)使用一個已經存在的類,但如果它的接口,也就是它的方法和你的要求不相同時,就應該考慮使用適配器
--->備忘錄模式(Memento):在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態,這樣以后就可將該對象恢復到原先保存的狀態。
1)把要保存的細節給封裝在了Memento中了,哪一天要更改保存的細節也不用影響客戶端。
2)Memento模式比較適用于功能比較復雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性中的一部分時,Originator可以根據保存的Memento信息還原到前一狀態。
3)如果在某個系統中使用命令模式時,需要實現命令的撤銷功能,那么命令模式可以使用備忘錄模式來存儲可撤銷操作的狀態。
4)當角色的狀態改變的時候,有可能這個狀態無效,這時候就可以使用暫時存儲起來的備忘錄將狀態復原。
–>組合模式(Composite):將對象組合成樹形結構以表示“部分——整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。
1)組合模式定義了包含人力資源部和財務部這些基本對象和分公司、辦事處等組合對象的類層次結構。基本對象可以被組合成更復雜的組合對象,而這個組合對象又可以被組合,這樣不斷地遞歸下去,客戶端代碼中,任何用到基本對象的地方度可以使用組合對象了。
2)用戶不用關心到底是處理一個葉子還是處理一個組合組件,也就是用不著為定義組合而寫一些選擇判斷語句。
3)組合模式讓客戶可以一致地使用組合結構和單個對象。
比如 :總公司,總公司財務部,總公司人力資源部;華東分公司,財務部,人力資源部,南京辦事處(財務部,人力資源部)
–>單例模式:Singleton
保證一個類僅有一個實例,并提供一個訪問它的全局訪問點!
1)通常我們可以讓一個全局變量使得一個對象被訪問,但它不能防止你實例化多個對象。一個最好的辦法是,讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例可以被創建,并且它可以提供一個訪問該實例的方法。
具體做法是:把構造方法聲明為private類型,只提供一個public類型getInstance()方法,判斷是否為唯一的實例,讓該類自己負責生成!這是懶漢式單例.
2)在靜態初始化的方式是在自己被加載是就將自己實例化,所以被形象地稱之為餓漢式單例類!
---> 橋接模式:(Bridge)將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
合成/聚合復用原則:盡量使用合成/聚合,盡量不要使用類繼承!
1)聚合(Aggregation):表示一種弱的“擁有”關系,體現的是A對象可以包含B對象,但B對象不是A對象的一部分;比如,大雁和雁群。
2)合成(組合 composition):則是一種強的“擁有”關系,體現了嚴格的部分和整體的關系,部分和整體的生命周期一樣!比如,大雁和翅膀就是部分和整體的關系,它們有相同的生命周期。
3)合成/聚合復用原則的好處是,優先使用對象的合成/聚合將有助于你保持每個類被封裝,并被集中在單個任務上。這樣類和類繼承層次會保持較小規模,并且不太可能增長為不可控制的龐然大物!
4)你要學會用對象的職責,而不是結構來考慮問題。繼承關系是一種強耦合的結構,父類變,子類就必須要變。
---》命令模式(Command):將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。
1) 命令模式能比較容易地設計一個命令隊列;
2)在需要的情況下,可以較容易地將命令記入日志;
3)允許接受請求的一方決定是否要否決請求。
4)可以容易地實現對請求的撤銷和重做;
5)由于加入新的具體命令類不影響其他的類,因此增加新的具體命令類很容易。
命令模式把請求一個操作的對象與知道怎么執行一個操作的對象分割開。
敏捷開發原則告訴我們,不要為代碼添加基于猜測的、實際不需要的功能。如果不清楚一個系統是否需要命令模式,一般不要著急去實現它,事實上,在需要的時候通過重構實現這個模式并不困難,只有在真正需要如撤銷/恢復操作等功能時,把原來的代碼重構為命令模式才有意義。
---》指責鏈模式(Chain of Responsiblility):使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
1)接受者和發送者都沒有對方的明確信息,且鏈中的對象自己也并不知道鏈的結構,結果是職責鏈可簡化對象的相互連接,他們僅保持一個指向其后繼者的引用,而不需保持它所有的候選接收者的引用,則會大大降低了耦合度。
2)我感覺由于是在客戶端來定義鏈的結構,我可以隨時增加或者修改處理一個請求的結構,增強了給對象指派指責的靈活性。
3)這的確很靈活,不過要當心,一個請求極有可能到了鏈的末端都得不到處理,或者因為沒有正確配置而得不到處理,這就很糟糕了。
案例:小菜請求加薪1000,經理無權作主,向人力資源總監請示,總監也無權作主,只能想總經理匯報,總經理開始不同意(小于500才行),最后經過經理的建議,同意了!
---->中介者模式(Mediator):用一個中介對象來封裝一系列的對象交互。中介者使得各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
1)通過中介者對象,可以將系統的網狀結構變成以中介者為中心的星形結構,每個具體對象不再通過直接的聯系與另一個對象發生相互作用,而是通過"中介著“對象與另一個對象發生相互作用。中介者對象的設計,使得系統的結構不會因為新對象的引入造成大量的修改工作。
2)迪米特法則:如果兩個類不必彼此直接通信,那么這兩個類就不應當發生直接的相互作用。如果其中一個類需要調用另一個類的話,可以通過第三方(也就是中介者)來發生關系,而不必直接通信。
3)中介者模式很容易在系統中應用,也很容易在系統中誤用。當系統出現了“多對多”交互復雜的對象群時,不要急于使用中介者模式,而是要先反思你的系統在設計上是不是合理。
4)由于把對象如何協作進行了抽象,將中介作為一個獨立的概念并將其封裝在一個對象中,這樣關注的對象就從對象各本身的行為轉移到他們之間的交互上來,也就是站在一個更宏觀的角度去看待系統。
5)由于ConcretetMediator控制了集中化,于是就把交互復雜性變成了中介者的復雜性,則這就使得中介者會變得比任何一個ConcreteColleague都復雜。
案例:聯合國安全理事會處理美國和伊拉克問題。
---》享元模式:運用共享技術有效地支持大量細粒度的對象。
1)如果一個應用程序使用了大量的對象,而大量的這些對象造成了很大的存儲開銷時就應該考慮使用;、
2)如果對象的大多數狀態可以是外部狀態,如果刪除對象的外部狀態,那麼可以用相對較少的共享對象取代很多組對象,此時可以考慮使用享元模式;
---》解釋器模式:給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
1)如果一種特定類型的問題發生的頻率足夠高,那么可能就值得將該問題的各個實例表述為一個簡單語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。
2)而所謂的解釋器模式,正則表達式就是它的一種應用,解釋器為正則表達式定義一個文法,如何表示一個特定的正則表達式,以及如何解釋這個正則表達式。
3)通常當有一個語言需要解釋執行,并且你可將該語言中的句子表示為一個抽象語法樹時,可使用解釋器模式;
4)用了解釋器模式,就意味著可以很容易地改變和擴展文法,因為該模式使用類來表示文法規則,你可使用繼承來改變或擴展該文法。也比較容易實現文法,因為定義綽想語法樹中各個節點的類的實現大體類似,這些類度易于直接編寫;
5)說白了,解釋器模式就是就是將這樣的一句話,轉變成實際的命令程序執行而已。而不用解釋起模式本來也可以分析,但通過繼承抽象表達式的方式,由于依賴倒轉原則,使得對文法的擴展和維護都帶來了方便;
6)解釋器模式也有不足的,解釋器模式為文法中的每一條規則至少定義了一個類,因此包含許多規則的文法可能難以管理和維護。建議當文法非常復雜時,使用其他的技術如語法分析程序或編譯器生成器來處理;
案例:音樂播放器,正則表達等
---》訪問者模式:它講的是表示一個作用于某對象結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作;
1)訪問者模式適用于數據結構相對穩定的系統;它把數據結構和作用于結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化;
2)訪問者模式的目的是要把處理從數據結構分離出來,很多系統可以按照算法和數據結構分開,如果這樣的系統有比較穩定的數據結構,又有易于變化的算法的話,使用訪問者模式就是比較合適的,因為訪問者模式使得算法操作的增加變得容易;
3)訪問者模式的有點就是增加新的操作很容易,因為增加信的操作就意味著增加一個信的訪問者,訪問者模式將有關的行為集中到一個訪問者對象中。
4)GOF四人中的一個作者就說過:‘大多時候你并不需要訪問者模式,但當一旦你需要訪問者模式時,那就是真的需要它了!‘;事實上,我們很難找到數據結構不變化的情況,所以用訪問者模式的機會也就不太多了。
- 職業生涯
- 如何提升你的能力?給年輕程序員的幾條建議
- 那些年,那些事
- 阿里巴巴離職DBA 35歲總結的職業生涯
- 人生的四種選擇
- 程序人生的四個象限和兩條主線
- 幾縷代碼與閑思
- 張小龍-學習筆記
- Web前端
- 移動Web手冊
- 精通CSS: 高級Web標準解決方案
- 悟透JavaScript
- 架構設計
- 大型網站技術架構
- 周愛民-大道至簡
- RESTful Web Services Cookbook - 讀書筆記
- 大話設計模式
- Unix編程藝術
- 把程序員修煉之道讀薄
- 學習能力
- 奇特的一生:讀書筆記
- zhh-看源碼那些事
- 一個創業者怎么看待讀書和寫作
- 程序員修煉之道
- 2015/1/5 頭腦風暴
- 書單計劃
- 2014年我讀過的那些書
- 我的后端開發書架2015
- 別人的書單
- 讀書筆記
- 浪潮之巔
- 達內時期自己筆記整理
- Effective Java
- 打造facebook: 讀書筆記
- 面試整理
- 阿里面試的一點感受
- 騰訊的三輪面試
- 三十之惑–面霸
- 前端面試問題匯總
- 八爪網絡面試總結
- 2015面試總結總結
- 找工作流程梳理
- 最全前端面試問題及答案總結
- 前端開發面試題收集
- 百度web前端--2015一面
- 百度web前端--2015二面