23种经典设计模式都有哪些,如何分类?Java设计模式相关面试
23種經(jīng)典設(shè)計模式都有哪些,如何分類?
23種經(jīng)典設(shè)計模式都有哪些,如何分類?
java常用的設(shè)計模式?說明工廠模式
Java 中的23 種設(shè)計模式:
Factory(工廠模式), Builder(建造模式), Factory Method(工廠方法模式),
Prototype(原始模型模式),Singleton(單例模式), Facade(門面模式),
Adapter(適配器模式), Bridge(橋梁模式), Composite(合成模式),
Decorator(裝飾模式), Flyweight(享元模式), Proxy(代理模式),
Command(命令模式), Interpreter(解釋器模式), Visitor(訪問者模式),
Iterator(迭代子模式), Mediator(調(diào)停者模式), Memento(備忘錄模式),
Observer(觀察者模式), State(狀態(tài)模式), Strategy(策略模式),
Template Method(模板方法模式), Chain Of Responsibleity(責(zé)任鏈模式)
工廠模式:工廠模式是一種經(jīng)常被使用到的模式,根據(jù)工廠模式實現(xiàn)的類可以根據(jù)提供的數(shù)據(jù)生成一組類中某一個類的實例,通常這一組類有一個公共的抽象父類并且實現(xiàn)了相同的方法,但是這些方法針對不同的數(shù)據(jù)進行了不同的操作。首先需要定義一個基類,該類的子類通過不同的方法實現(xiàn)了基類中的方法。然后需要定義一個工廠類,工廠類可以根據(jù)條件生成不同的子類實例。當?shù)玫阶宇惖膶嵗?#xff0c;開發(fā)人員可以調(diào)用基類中的方法而不必考慮到底返回的是哪一個子類的實例。
Spring 框架中都用到了哪些設(shè)計模式?
Spring 框架中都用到了哪些設(shè)計模式?
Spring框架中使用到了大量的設(shè)計模式,下面列舉了比較有代表性的:
代理模式—在AOP和remoting中被用的比較多。
單例模式—在spring配置文件中定義的bean默認為單例模式。
模板方法—用來解決代碼重復(fù)的問題。比如. RestTemplate, JmsTemplate, JpaTemplate。
前端控制器—Spring提供了DispatcherServlet來對請求進行分發(fā)。
視圖幫助(View Helper )—Spring提供了一系列的JSP標簽,高效宏來輔助將分散的代碼整合在視圖里。
依賴注入—貫穿于BeanFactory / ApplicationContext接口的核心理念。
工廠模式—BeanFactory用來創(chuàng)建對象的實例。
Java設(shè)計模式相關(guān)面試
這里面試一些簡單的面試題
1.接口是什么?為什么要使用接口而不是直接使用具體類?
接口用于定義 API。它定義了類必須得遵循的規(guī)則。同時,它提供了一種抽象,因為客戶端只使用接口,這樣可以有多重實現(xiàn),如 List 接口,你可以使用可隨機訪問的 ArrayList,也可以使用方便插入和刪除的 LinkedList。接口中不允許寫代碼,以此來保證抽象,但是 Java 8 中你可以在接口聲明靜態(tài)的默認方法,這種方法是具體的。
2.java中,抽象類與接口之間有什么區(qū)別?
1.一個類可以實現(xiàn)多個接口 ,但卻只能繼承最多一個抽象類。
2.抽象類可以包含具體的方法 , 接口的所有方法都是抽象的。
3.抽象類可以聲明和使用字段 ,接口則不能,但接口可以創(chuàng)建靜態(tài)的final常量。
4.接口的方法都是public的,抽象類的方法可以是public,protected,private或者默認的package;
5.抽象類可以定義構(gòu)造函數(shù),接口卻不能。
3.除了單例模式,你在生產(chǎn)環(huán)境中還用過什么設(shè)計模式?
這需要根據(jù)你的經(jīng)驗來回答。一般情況下,你可以說依賴注入,工廠模式,裝飾模式或者觀察者模式,隨意選擇你使用過的一種即可。不過你要準備回答接下的基于你選擇的模式的問題。
1、開閉原則(Open Close Principle)
開閉原則就是說對擴展開放,對修改關(guān)閉。在程序需要進行拓展的時候,不能去修改原有的代碼,實現(xiàn)一個熱插拔的效果。所以一句話概括就是:為了使程序的擴展性好,易于維護和升級。想要達到這樣的效果,我們需要使用接口和抽象類,后面的具體設(shè)計中我們會提到這點。
2、里氏代換原則(Liskov Substitution Principle)
里氏代換原則(Liskov Substitution Principle LSP)面向?qū)ο笤O(shè)計的基本原則之一。 里氏代換原則中說,任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。 LSP是繼承復(fù)用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復(fù)用,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為。里氏代換原則是對“開-閉”原則的補充。實現(xiàn)“開-閉”原則的關(guān)鍵步驟就是抽象化。而基類與子類的繼承關(guān)系就是抽象化的具體實現(xiàn),所以里氏代換原則是對實現(xiàn)抽象化的具體步驟的規(guī)范。—— From Baidu 百科
3、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)
這個是開閉原則的基礎(chǔ),具體內(nèi)容:真對接口編程,依賴于抽象而不依賴于具體。
4、接口隔離原則(Interface Segregation Principle)
這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。還是一個降低類之間的耦合度的意思,從這兒我們看出,其實設(shè)計模式就是一個軟件的設(shè)計思想,從大型軟件架構(gòu)出發(fā),為了升級和維護方便。所以上文中多次出現(xiàn):降低依賴,降低耦合。
5、迪米特法則(最少知道原則)(Demeter Principle)
為什么叫最少知道原則,就是說:一個實體應(yīng)當盡量少的與其他實體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對獨立。
6、合成復(fù)用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式,而不是使用繼承
5.什么情況下會違反迪米特法則?為什么會有這個問題?
迪米特法則建議“只和朋友說話,不要陌生人說話”,以此來減少類之間的耦合。
6.適配器模式是什么?什么時候使用?
適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式,它結(jié)合了兩個獨立接口的功能。適配器模式提供對接口的轉(zhuǎn)換。如果你的客戶端使用某些接口,但是你有另外一些接口,你就可以寫一個適配去來連接這些接口。
7.適配器模式與裝飾器模式有什么區(qū)別?
雖然適配器模式和裝飾器模式的結(jié)構(gòu)類似,但是每種模式的出現(xiàn)意圖不同。適配器模式被用于橋接兩個接口,而裝飾模式的目的是在不修改類的情況下給類增加新的功能。
裝飾者模式: 動態(tài)地將責(zé)任附加到對象上,若要擴展功能,裝飾者模提供了比繼承更有彈性的替代方案。
通俗的解釋: 裝飾模式就是給一個對象增加一些新的功能,而且是動態(tài)的,要求裝飾對象和被裝飾對象實現(xiàn)同一個接口,裝飾對象持有被裝飾對象的實例。
適配器模式: 將一個類的接口,轉(zhuǎn)換成客戶期望的另一個接口。適配器讓原本接口不兼容的類可以合作無間。
適配器模式有三種:類的適配器模式、對象的適配器模式、接口的適配器模式。
通俗的說法:適配器模式將某個類的接口轉(zhuǎn)換成客戶端期望的另一個接口表示,目的是消除由于接口不匹配所造成的類的兼容性問題。
舉例如下:
1、適配器模式
//file 為已定義好的文件流
FileInputStream fileInput = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInput);
以上就是適配器模式的體現(xiàn),FileInputStream是字節(jié)流,而并沒有字符流讀取字符的一些api,因此通過InputStreamReader將其轉(zhuǎn)為Reader子類,因此有了可以操作文本的文件方法。
2、裝飾者模式
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);構(gòu)造了緩沖字符流,將FileInputStream字節(jié)流包裝為BufferedReader過程就是裝飾的過程,剛開始的字節(jié)流FileInputStream只有read一個字節(jié)的方法,包裝為inputStreamReader后,就有了讀取一個字符的功能,在包裝為BufferedReader后,就擁有了read一行字符的功能。
8.適配器模式和代理模式之間有什么不同?
這個問題與前面的類似,適配器模式和代理模式的區(qū)別在于他們的意圖不同。由于適配器模式和代理模式都是封裝真正執(zhí)行動作的類,因此結(jié)構(gòu)是一致的,但是適配器模式用于接口之間的轉(zhuǎn)換,而代理模式則是增加一個額外的中間層,以便支持分配、控制或智能訪問。
9.什么事模板方法模式?
模板方法提供算法的框架,你可以自己去配置或定義步驟。例如,你可以將排序算法看做是一個模板。它定義了排序的步驟,但是具體的比較,可以使用 Comparable 或者其語言中類似東西,具體策略由你去配置。列出算法概要的方法就是眾所周知的模板方法。
10.什么時候使用訪問者模式?
訪問者模式用于解決在類的繼承層次上增加操作,但是不直接與之關(guān)聯(lián)。這種模式采用雙派發(fā)的形式來增加中間層。
11.什么時候使用組合模式?
組合模式使用樹結(jié)構(gòu)來展示部分與整體繼承關(guān)系。它允許客戶端采用統(tǒng)一的形式來對待單個對象和對象容器。當你想要展示對象這種部分與整體的繼承關(guān)系時采用組合模式。
12.繼承和組合之間有什么不同?
雖然兩種都可以實現(xiàn)代碼復(fù)用,但是組合比繼承共靈活,因為組合允許你在運行時選擇不同的實現(xiàn)。用組合實現(xiàn)的代碼也比繼承測試起來更加簡單。
13.描述Java中的重載與重寫?什么時候用重載,什么時候用重寫?
重載和重寫都允許你用相同的名稱來實現(xiàn)不同的功能,但是重載是編譯時活動,而重寫是運行時活動。你可以在同一個類中重載方法,但是只能在子類中重寫方法。重寫必須要有繼承。
對有經(jīng)驗的Java設(shè)計師來說,這是一個相當簡單的問題。如果你看到一個類的不同實現(xiàn)有著不同的方式來做同一件事,那么就應(yīng)該用重寫(overriding),而重載(overloading)是用不同的輸入做同一件事。在Java中,重載的方法簽名不同,而重寫并不是。
14.Java中,嵌套公共靜態(tài)類與頂級類有什么不同?
類的內(nèi)部可以有多個嵌套公共靜態(tài)類,但是一個 Java 源文件只能有一個頂級公共類,并且頂級公共類的名稱與源文件名稱必須一致。
15.OOP中的組合、聚合和關(guān)聯(lián)有什么區(qū)別?
如果兩個對象彼此有關(guān)系,就說他們是彼此相關(guān)聯(lián)的。組合和聚合是面向?qū)ο笾械膬煞N形式的關(guān)聯(lián)。組合是一種比聚合更強力的關(guān)聯(lián)。組合中,一個對象是另一個的擁有者,而聚合則是指一個對象使用另一個對象。如果對象 A 是由對象 B 組合的,則 A 不存在的話,B一定不存在,但是如果 A 對象聚合了一個對象 B,則即使 A 不存在了,B 也可以單獨存在。
16.給我一個符合開閉原則的設(shè)計模式的例子?
開閉原則要求你的代碼對擴展開放,對修改關(guān)閉。這個意思就是說,如果你想增加一個新的功能,你可以很容易的在不改變已測試過的代碼的前提下增加新的代碼。有好幾個設(shè)計模式是基于開閉原則的,如策略模式,如果你需要一個新的策略,只需要實現(xiàn)接口,增加配置,不需要改變核心邏輯。一個正在工作的例子是 Collections.sort() 方法,這就是基于策略模式,遵循開閉原則的,你不需為新的對象修改 sort() 方法,你需要做的僅僅是實現(xiàn)你自己的 Comparator 接口。
17.使用工廠模式最主要的好處是什么?你在哪里使用?
工廠模式的最大好處是增加了創(chuàng)建對象時的封裝層次。如果 你使用工廠來創(chuàng)建對象,之后你可以使用更高級和更高性能的實現(xiàn)來替換原始的產(chǎn)品實現(xiàn)或類,這不需要在調(diào)用層做任何修改。可以看我的文章工廠模式得更詳細的解釋和和了解更多的好處。
18.工廠模式與抽象工廠模式的區(qū)別?
首先來看看這兩者的定義區(qū)別:
工廠模式:定義一個用于創(chuàng)建對象的借口,讓子類決定實例化哪一個類
抽象工廠模式:為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個接口,而且無需指定他們的具體類
再來看看工廠方法模式與抽象工廠模式對比:
| 針對的是一個產(chǎn)品等級結(jié)構(gòu) | 針對的是面向多個產(chǎn)品等級結(jié)構(gòu) |
| 一個抽象產(chǎn)品類 | 多個抽象產(chǎn)品類 |
| 可以派生出多個具體產(chǎn)品類 | 每個抽象產(chǎn)品類可以派生出多個具體產(chǎn)品類 |
| 一個抽象工廠類,可以派生出多個具體工廠類 | 一個抽象工廠類,可以派生出多個具體工廠類 |
| 每個具體工廠類只能創(chuàng)建一個具體產(chǎn)品類的實例 | 每個具體工廠類可以創(chuàng)建多個具體產(chǎn)品類的實例 |
18.什么時候使用享元模式?
享元模式通過共享對象來避免創(chuàng)建太多的對象。為了使用享元模式,你需要確保你的對象是不可變的,這樣你才能安全的共享。JDK 中 String 池、Integer 池以及 Long 池都是很好的使用了享元模式的例子。
19 什么是設(shè)計模式?你是否在你的代碼里面使用過任何設(shè)計模式?
設(shè)計模式是世界上各種各樣程序員用來解決特定設(shè)計問題的嘗試和測試的方法。設(shè)計模式是代碼可用性的延伸。
20 你可以說出幾個在JDK庫中使用的設(shè)計模式嗎?
裝飾器設(shè)計模式(Decorator design pattern)被用于多個Java IO類中。單例模式(Singleton pattern)用于Runtime,Calendar和其他的一些類中。工廠模式(Factory pattern)被用于各種不可變的類如Boolean,像Boolean.valueOf,觀察者模式(Observer pattern)被用于Swing和很多的事件監(jiān)聽中。
21.Java中什么事單例設(shè)計模式?用Java寫出線程安全的單例
單例對象(Singleton)是一種常用的設(shè)計模式。在Java應(yīng)用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。這樣的模式有幾個好處:
1、某些類創(chuàng)建比較頻繁,對于一些大型的對象,這是一筆很大的系統(tǒng)開銷。
2、省去了new操作符,降低了系統(tǒng)內(nèi)存的使用頻率,減輕GC壓力。
3、有些類如交易所的核心交易引擎,控制著交易流程,如果該類可以創(chuàng)建多個的話,系統(tǒng)完全亂了。(比如一個軍隊出現(xiàn)了多個司令員同時指揮,肯定會亂成一團),所以只有使用單例模式,才能保證核心交易服務(wù)器獨立控制整個流程。
單例模式重點在于在整個系統(tǒng)上共享一些創(chuàng)建時較耗資源的對象。整個應(yīng)用中只維護一個特定類實例,它被所有組件共同使用。Java.lang.Runtime是單例模式的經(jīng)典例子。你可以在我的文章Java單例模式的10個問題看到更多的問題和討論。從Java 5開始你可以使用枚舉(enum)來實現(xiàn)線程安全的單例。
http://blog.csdn.net/cselmu9/article/details/5136694622在Java中,什么叫觀察者設(shè)計模式(observer design pattern)?
觀察者模式是基于對象的狀態(tài)變化和觀察者的通訊,以便他們作出相應(yīng)的操作。簡單的例子就是一個天氣系統(tǒng),當天氣變化時必須在展示給公眾的視圖中進行反映。這個視圖對象是一個主體,而不同的視圖是觀察者。可以在這篇文章中看到Java觀察者模式的完整例子。
23什么是責(zé)任鏈設(shè)計模式?
責(zé)任鏈模式(Chain of Responsibility Pattern)為請求創(chuàng)建了一個接收者對象的鏈。這種模式給予請求的類型,對請求的發(fā)送者和接收者進行解耦。這種類型的設(shè)計模式屬于行為型模式。在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者,依此類推。
Java高級面試設(shè)計模式
1. 舉出一個例子,在這種情況你會更傾向于使用抽象類,而不是接口?
這是很常用但又是很難回答的設(shè)計面試問題。接口和抽象類都遵循”面向接口而不是實現(xiàn)編碼”設(shè)計原則,它可以增加代碼的靈活性,可以適應(yīng)不斷變化的需求。下面有幾個點可以幫助你回答這個問題:
在一些對時間要求比較高的應(yīng)用中,傾向于使用抽象類,它會比接口稍快一點。
如果希望把一系列行為都規(guī)范在類繼承層次內(nèi),并且可以更好地在同一個地方進行編碼,那么抽象類是一個更好的選擇。有時,接口和抽象類可以一起使用,接口中定義函數(shù),而在抽象類中定義默認的實現(xiàn)。
。
2. 設(shè)計一個販賣機,可以接收不同的貨幣,出售不同的產(chǎn)品?
這是一個開放設(shè)計問題,你可以作為練習(xí),嘗試著寫出設(shè)計文檔、代碼和JUnit測試而不是只是解決這個問題,看看它花了你多少時間得到解決方案和得到需要的原形。理想情況下,這個問題應(yīng)該可以在3個小時內(nèi)解決,至少應(yīng)該得到一個可以運行的版本。
3. 你有一個Smartphone類,可以派生如IPhone、AndroidPhone、WindowsMobilePhone類它還可以是一些有著品牌的手機名稱,你會怎么設(shè)計這個類系統(tǒng)呢。
這是另外一個設(shè)計模式練習(xí),你可以應(yīng)用你的面向?qū)ο笤O(shè)計技巧來得到一個設(shè)計,這個設(shè)計需要足夠靈活能夠支持未來產(chǎn)品的擴展,足夠穩(wěn)定能夠支持在現(xiàn)有模型進行修改。
5. 設(shè)計一個ATM機?
我們所有人都使用ATM(自動柜員機)。想想你會怎么設(shè)計一個ATM?就設(shè)計金融系統(tǒng)來說,必須知道它們應(yīng)該在任何情況下都能夠如期工作。不管是斷電還是其他情況,ATM應(yīng)該保持 正確的狀態(tài)(事務(wù)) , 想想 加鎖(locking)、事務(wù)(transaction)、錯誤條件(error condition)、邊界條件(boundary condition) 等等。盡管你不能想到具體的設(shè)計,但如果你可以指出非功能性需求,提出一些問題,想到關(guān)于邊界條件,這些都會是很好的一步。
6. 你正在寫一些類提供市場數(shù)據(jù),你知道你可以不定時切換不同的廠商如Reuters、wombat或者直接的批發(fā)商,你會如何設(shè)計你的市場數(shù)據(jù)系統(tǒng)。
這是一個非常有趣的設(shè)計面試問題,并且真的在一家大的投資銀行問到過,如果你是用Java編碼的話這是一個相當平常的場景。最主要的一點是你要有一個MarketData接口,它會有調(diào)用端需要的方法如:getBid()、getPrice()、getLevel()等等,而MarketData應(yīng)該由一個MarketDataProvider通過 依賴注入(dependency injection) 組成。因此,當你修改你的MarketData 提供器(MarketDataProvider)時,調(diào)用端不會受影響,因為它們是通過MarketData接口或類的方法來訪問的。
7. 在Java中,為什么不允許從靜態(tài)方法中訪問非靜態(tài)變量?
你在Java中不能從靜態(tài)上下文訪問非靜態(tài)數(shù)據(jù)只是因為非靜態(tài)變量是跟具體的對象實例關(guān)聯(lián)的,而靜態(tài)的卻沒有和任何實例關(guān)聯(lián)。你可以看我的文章為什么在靜態(tài)上下文中不能訪問非靜態(tài)變量查看詳細的討論。
8. 在Java中設(shè)計一個并發(fā)規(guī)則的pipeline?
并發(fā)編程或并發(fā)設(shè)計這些天很火,它可以充分利用現(xiàn)在不斷提升的高級處理器的處理能力,而Java成為一個多線程語言也從這種情況獲益良多。設(shè)計一個并發(fā)系統(tǒng)需要記住的最關(guān)鍵的點是線程安全,不可變性,本地變量和避免使用static或者類變量(instance variables)。你只需要想著每一類都可以同時被多個線程同時執(zhí)行,所以最好的做法就是每一個線程都處理自己的數(shù)據(jù) ,不跟其他數(shù)據(jù)交互,并且運行時只需要最小的同步保證。這個問題可以涉及到從最初的討論到完整的類和接口編碼,但只要你記住并發(fā)中最重要的點和問題如,競爭條件(race condition)、死鎖(deadlock)、內(nèi)存交互問題(memory interference)、原子性、ThreadLocal變量等,你都可以回答它。
總結(jié)
以上是生活随笔為你收集整理的23种经典设计模式都有哪些,如何分类?Java设计模式相关面试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python精要(69)-turtle(
- 下一篇: 汇编解析(3)-nasm基础、物理地址