1. 程式人生 > >面試被問設計模式?不要怕看這裡:工廠模式

面試被問設計模式?不要怕看這裡:工廠模式

上一篇中,我介紹了單例模式的關鍵點,掌握了這些關鍵點,面試被問到單例肯定就沒太大問題了,我們先來回顧一下:

單例設計模式的關鍵點

一.私有建構函式

二.宣告靜態單例物件

三.構造單例物件之前要加鎖(lock一個靜態的object物件,某些語言可以宣告同步執行,其實是一個目的)

四.需要兩次檢測單例例項是否已經被構造,分別在鎖之前和鎖之後

好了,本文將向大家來討論一下工廠模式,並且歸納工廠模式的關鍵點。

我在面試的時候,有時候會問到候選人有沒有熟悉的設計模式,一般大部分候選人會選擇說熟悉單例和工廠(也有部分人會說熟悉觀察者),如果我進一步問候選人是如何應用工廠模式的,10個候選人有10個會舉連線Sqlserver,Oracle,Mysql等不同資料庫時會用工廠模式產生不同的連線的例子。

OMG,我知道大家都是愛學習的同學,但是大家為什麼不仔細想想,網上一搜一大堆的例子,你能看到,別人難道看不到?我不知道大家能不能感受,作為一個面試官,問到一個問題的時候,所有候選人都用同一個例子來回答你的感受。。。

如果我進一步問,工廠模式中,簡單工廠,工廠和抽象工廠的區別,以及每種工廠的優劣勢時,候選人基本都會蒙圈。如果自己沒有使用過,甚至使用過沒有認真思考過,肯定是回答不上來的。好吧,下面我就來跟大家講講工廠模式。

工廠模式理論我不長篇大論了。其核心功能是根據“需求”生產“產品”,還記得我上一篇說的,設計模式的核心是解耦嗎?工廠模式就是為了解耦“需求”和“產品”,但是別忘了,工廠模式工廠模式,還有一個重要元素,就是“工廠”,所以工廠模式的核心思想,就是解耦“需求”“工廠”和“產品”。

工廠模式,實際上也會根據業務情景不同會有不同的實現方式。一般分為3種。簡單工廠,工廠和抽象工廠。顧名思義,這三種從簡單到抽象,名稱越來越高大上,實現方式肯定是越來越複雜,所以,我們可以得到第一個結論,三種工廠的實現是越來越複雜的。

先來看看簡單工廠。廢話不多,擼程式碼:

123456789101112131415161718192021222324252627282930313233343536373839404142 intprodNo;publicSimpleFactory(intprodNo)//構造工廠時告知工廠產品標識{this.prodNo=prodNo;}publicIProduct GetProduct(){switch(prodNo)//根據產品標識生產產品{default:returnnewProductA();case1:returnnewProductA();case2:returnnewProductB();}}}//產品AclassProductA:IProduct{//產品屬性//......}//產品BclassProductB:IProduct{//產品屬性//......}//產品介面interfaceIProduct{//產品方法//......}

注意,這段例子程式碼當然還可以寫的簡單點,我完全可以在簡單工廠中直接返回字串而避免寫產品類和產品介面。但是即便是真實的業務場景是這樣(真的只需要返回字串或者數字什麼的),大家還是把產品類和工廠類分開,這樣才是使用工廠模式的初衷,也就是實現解耦。

那麼大家看看這段簡單工廠的例子,如果我現在問,這個會有什麼問題,該如何回答呢?提示一下,如果說來了一個需求,增加一個產品C,該如何辦?沒錯,簡單工廠的問題就在於swich case(或者if else)。每當新增一種產品時,你都需要去維護工廠中的判斷語句,造成的後果就是可能這個工廠類會非常非常長,各種判斷全部擠在一起,給擴充套件和維護帶來很多麻煩。說白了,你的產品和工廠還是沒有完全解耦,繫結在一起的。所以,我們得到了第二個結論:簡單工廠通過構造時傳入的標識來生產產品,不同產品都在同一個工廠中生產,這種判斷會隨著產品的增加而增加,給擴充套件和維護帶來麻煩。那麼,如何解決這個問題呢?

你猜對了,工廠模式可以解決這個問題,程式碼擼上:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 interfaceIFactory//工廠介面{IProduct GetProduct();}//A工廠類publicclassFactoryA:IFactory{IProduct productA;publicFactoryA(){this.productA=newProductA();}publicIProduct GetProduct()//A工廠生產A產品{returnthis.productA;}}//B工廠類publicclassFactoryB:IFactory{IProduct productB;publicFactoryB(){this.productB=newProductB();}publicIProduct GetProduct()//B工廠生產B產品{returnthis.productB;}}//產品介面publicinterfaceIProduct{//產品方法//......}//產品ApublicclassProductA:IProduct{//產品屬性//......}//產品BpublicclassProductB:IProduct{//產品屬性//......}

仔細觀察這段程式碼,在工廠模式中,已經將工廠類分開,不再將所有產品在同一工廠中生產,這樣就解決了簡單工廠中不停的switch case的問題。如果說來了一個C產品,那麼我們只需要寫一個C工廠和C產品,在呼叫時用C工廠生產C產品即可,A和B工廠和產品完全不受影響。OK,優化說完了,但是還是有問題。

問題在哪裡呢?當業務需求是需要生產產品族的時候,工廠就不再適合了。首先我們搞清楚何謂產品族和產品等級結構。舉個例子來說,比如三星是一個品牌,三星生產洗衣機,電視,冰箱;格力也是一個品牌,格力也生產洗衣機,電視,冰箱。那麼,三星工廠和格力工廠生產的2個品牌的洗衣機,就在洗衣機這種產品的產品等級結構中(當然洗衣機產品等級結構中還有LG,海爾,三菱等等不同的品牌的工廠的產品),所以,洗衣機就是一個產品等級。那麼三星生產的三星洗衣機,三星電視機,三星冰箱就是三星這個工廠的產品族。可能還會有西門子工廠產品族,格力工廠產品族,美的工廠產品族等等。

好了,搞清楚了產品等級結構和產品族,我們得到第三個結論:工廠模式無法解決產品族和產品等級結構的問題。再回過頭來看抽象工廠模式。如果如上所述,業務場景是需要實現不同的產品族,並且實現產品等級結構,就要用到抽象工廠模式了。還是來看程式碼:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 //工廠介面,即抽象工廠interfaceIFactory{IFridge CreateFridge();IAirCondition CreateAirCondition();}//三星的工廠,生產三星的產品族publicclassSamsungFactory:IFactory{publicIAirCondition CreateAirCondition(){returnnewSamsungAirCondition();//三星的工廠生產三星的空調}publicIFridge CreateFridge(){returnnewSamsungFridge();//三星的工廠生產三星的冰箱}}//格力的工廠,生產格力的產品族publicclassGreeFactry:IFactory{publicIAirCondition CreateAirCondition(){returnnewGreeAirCondition();//格力的工廠生產格力的空調}publicIFridge CreateFridge(){returnnewGreeFridge();//格力的工廠生產格力的冰箱}}//冰箱產品介面publicinterfaceIFridge{//冰箱產品介面//冰箱的action}//空調介面publicinterfaceIAirCondition{//空調產品介面//空調的action}//三星的冰箱publicclassSamsungFridge:IFridge{//三星冰箱的action和property}//格力的冰箱publicclassGreeFridge:IFridge{//格力冰箱的action和property}//三星的空調publicclassSamsungAirCondition:IAirCondition{//三星空調的action和property}//格力的空調publicclassGreeAirCondition:IAirCondition{//格力空調的action和property}

我們可以看到,在工廠模式中,一個工廠生產一個產品,所有的具體產品是由同一個抽象產品派生的,不存在產品等級結構和產品族的概念;而在抽象工廠中,同一個等級的產品是派生於一個抽象產品(即產品介面),一個抽象工廠派生不同的具體工廠,每個具體工廠生產自己的產品族(包含不同產品等級)。所以我們得到第四個結論,工廠模式中,一個工廠生產一個產品,所有產品派生於同一個抽象產品(或產品介面);而抽象工廠模式中,一個工廠生產多個產品,它們是一個產品族,不同的產品族的產品派生於不同的抽象產品(或產品介面)。

好了我們歸納一下,工廠模式實際上包含了3中設計模式,簡單工廠,工廠和抽象工廠,關鍵點如下:

一、三種工廠的實現是越來越複雜的

二、簡單工廠通過構造時傳入的標識來生產產品,不同產品都在同一個工廠中生產,這種判斷會隨著產品的增加而增加,給擴充套件和維護帶來麻煩

三、工廠模式無法解決產品族和產品等級結構的問題

四、抽象工廠模式中,一個工廠生產多個產品,它們是一個產品族,不同的產品族的產品派生於不同的抽象產品(或產品介面)。

好了,如果你能理解上面的關鍵點,說明你對工廠模式已經理解的很好了,基本上面試官問你工廠模式,你可以昂頭挺胸的說一番。但是,面試官怎麼可能會放過每一次虐人的機會?你仍然可能面臨下面的問題:

  1. 在上面的程式碼中,都使用了介面來表達抽象工廠或者抽象產品,那麼可以用抽象類嗎?有何區別?

從功能上說,完全可以,甚至可以用介面來定義行為,用抽象類來抽象屬性。抽象類更加偏向於屬性的抽象,而用介面更加偏向行為的規範與統一。使用介面有更好的可擴充套件性和可維護性,更加靈活實現鬆散耦合,所以程式設計原則中有一條是針對介面程式設計而不是針對類程式設計。

2. 到底何時應該用工廠模式

根據具體業務需求。不要認為簡單工廠是用switch case就覺得一無是處,也不要覺得抽象工廠比較高大上就到處套。我們使用設計模式是為了解決問題而不是炫技,所以根據三種工廠模式的特質,以及對未來擴充套件的預期,來確定使用哪種工廠模式。

3.說說你在專案中工廠模式的應用

如果你看了這篇文章,被問到這個問題時,還傻乎乎的去舉資料庫連線的例子,是要被打板子的。。。比如我之前做過一個旅遊產品的B2B網站,根據不同型別的業務形態,產品也是不同的,有國內跟團,出境跟團,國內自由行,出境自由行,郵輪五種產品,並且後面可能還會有門票,酒店,機票等等產品,其中有些聯絡也有些區別。

所以在面試中,我完全把工廠模式和我做的東西聯絡起來,如何建立工廠,如何生產不同的產品,如何擴充套件,如何維護等等。我想,把理論應用到實際,而且是真實業務邏輯中,給面試官的印象無論如何不會太差,甚至會對你刮目相看。

當然,即便是你沒有真的使用過,如果面試官問道了工廠模式,你仍然可以把你以往的經驗和設計模式聯絡起來回(hu)答(you)面試官,只要你理解了,把來龍去脈說清楚,並且可以回答問題,我想應該是可以令面試官滿意的。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式