本節書摘來自異步社群《.net程式員面試秘笈》一書中的第1章,面試題11,作者: 張雲翯, 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
.net程式員面試秘笈
【考點】工廠模式的了解,工廠模式在實際應用中的編寫。
【出現頻率】
【解答】
在軟體系統中,經常面臨着“一系列互相依賴的對象”的建立工作;同時由于需求的變化,往往存在着更多系列對象的建立工作。為了繞過正常對象的建立方法(new運算符建立執行個體),工廠模式提供一種“封裝機制”來減少使用程式和這種“多系列具體對象建立工作”的耦合性。
說明:
這裡的程式指客戶程式之類的使用者。
簡單工廠模式可以用于封裝建立執行個體的實作部分,在應用接口的程式中被廣泛使用,其應用模型如圖1.16所示。

為了處理更加複雜的情況,可以将圖中的産品進行再次細分為多個大類,用抽象類進行歸納,完成同大類産品共用代碼的複用。然後将工廠類也相應地分為多個大類,用抽象類進行歸納。将圖1.16改良後如圖1.17所示。

本圖假設将a産品和b産品作為兩大類産品(即将看作産品的具體實作類再次細分),每大類産品有兩個産品,如a産品有a1和a2。
為了說明工廠模式在應用程式中的具體表現,在ch01目錄下建立一個程式檔案,并命名為factory.cs,編寫代碼如程式1.12所示。
在指令行下編譯factory.cs後,執行factory程式,其效果如圖1.18所示。
本例聲明了多個類,代碼略顯複雜,但是隻要了解了圖1.17,其實也容易掌握。在代碼中,首先聲明了一個接口,即ihuman,其中含有兩個未實作的方法。實作接口的類是兩個抽象類,即children(孩子)類和adult(成年人)類,這兩個類分别歸納了boy類和girl類,以及man和woman類。接口的getstatus方法成員在抽象類中實作,而getfav方法則映射為抽象方法,被抽象類的派生類實作。最後通過humanfactory抽象類的兩個派生類,根據不同的參數傳遞,建立不同的執行個體引用,并傳回接口類型。
在主程式中,分别建立factory1類和factory2類的執行個體(f1和f2),并調用其gethuman方法。根據使用者的輸入決定建立哪個類的執行個體引用,并傳回一個接口類型引用變量(h1和h2)。接口類型的引用變量調用兩個方法時,使用者無法知道方法如何實作、由誰來實作。
【分析】
前面講解接口的時候,着重分析了bridge模式,接口可以簡單地完成意圖與實作的分離,以實作bridge模式。由于類可以實作多個接口,是以類可以通過多個接口向外界提供多組不同的功能。接口反映了面向對象程式設計的特征之一,即多态,多态指通過相同方法得到不同的表現。接口也反映了面向對象程式設計的另一個特征,即封裝,使用者并不清楚接口成員實作的細節,如以下代碼所示:
接口類型的abc可以引用不同類的執行個體,以緻相同的read方法可以有不同表現。但是以上代碼的程式部分中,使用者仍然需要用new運算符進行相應的執行個體化,同時,使用者還是知道read方法由哪個派生類實作。為了進一步分離意圖和實作,并對實作部分更好地封裝,簡單工廠模式可以進行一定的改良,添加代碼如下所示:
factory類封裝了将接口各個派生類執行個體化的代碼,這樣,使用者隻需要建立factory類的執行個體,并調用getbook方法即可。向getbook方法傳遞不同的整數類型參數,可以建立不同的執行個體引用,而這些執行個體都是ibook接口類型。如本例中,傳遞1将建立booka類的執行個體引用(ibook接口類型),傳遞2将建立bookb類的執行個體引用(ibook接口類型)。使用者隻知道傳遞數字來使用接口提供的不同功能,對内部實作卻一無所知。factory類則用于執行個體化各種類,相當于生産産品的工廠,其産品供接口類型的執行個體引用,這也是稱其為工廠模式的原因。
本例中工廠類的getbook方法使用switch條件分支判斷,然後傳回相應的執行個體引用,在執行個體種類很多的情況下不大适用。根據具體情況不同,可以考慮利用反射、泛型等方法進行改進。
本文僅用于學習和交流目的,不代表異步社群觀點。非商業轉載請注明作譯者、出處,并保留本文的原始連結。