<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">GOF的原廠模式是最基礎的一種建立型設計模式,其適用於建立同一介面的不同實現子類,</span>
其優點是:將使使用者更加方便使用,而不關心具體的建立邏輯
缺點是:每增加一個介面的子類,必須修改工程類的相關邏輯(後面我們用java的反射機制進行最佳化)
從上面UML圖看到,我們設定了一個Shape介面,並且實現了三個子類,我們通過ShapeFactory來根據不同的名稱返回不同的子類執行個體,通過FactoryPatternDemo進行的測試。邏輯很簡單,不再詳述。
public class ShapeFactory { //使用 getShape 方法擷取形狀類型的對象 public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; }}
基於以上面ShapeFactory的實現,我們思考到,如果我們再增加一個子類實現,那麼ShapeFactory必須進行相應的修改源碼,並重新進行編譯,這不是我們想要的結果。如果能不改變ShapeFactory的內容,而是將需要調用的子類寫在設定檔中多好,這樣ShapeFactory從設定檔中接收到需要返回的子類名稱,返回相應的子類執行個體。說到這裡,大家也許有點耳熟,這和spring中的依賴注入不很相似嗎,能想到這裡說明你很厲害了。不錯,這個就需要java的反射機制來實現(spring依賴注入的內部原理就是依賴java的反射機制),java.lang.Class類閃亮登場。
利於java.lang.Class類,我們可以通過Class.forName方法用類的詳細名稱(含包名)得到一個這個類的Class,之後就可以通過這個Class類進行一系列的操作了,執行個體化一個這個類的類對象newInstance()(調用不含參數的建構函式執行個體化),查看他的構造方法Constructor,方法Method,成員變數Field,執行Method(可能需要java.lang.reflect中的類)。
回到上面,我們如何最佳化上面的原廠模式,思路是這樣的,首先將將要調用的子類名放到設定檔中(好處是在改變調用的時候並不需要改變其他的代碼),然後在Factory中用Class解析這個類,並執行個體化返回。最後在Demo中進行調用。思路很簡單
properties檔案如下:
shape.className=factoryPattern.Rectangle
Factory代碼如下
public class ShapeFactory {public Shape getShape(String shapeClassName){Shape targetShape=null;Class oneClass=null;try {oneClass=Class.forName(shapeClassName);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();System.out.println("不能正確擷取類");}try {targetShape=(Shape) oneClass.newInstance();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();System.out.println("不能正確建立執行個體");}return targetShape;}
調用:
public static void main(String[] args) {String targetClassName=ClassNameConfig.getProperty("shape.className");System.out.println("targetClassName:"+targetClassName);ShapeFactory shapeFactory=new ShapeFactory();Shape targetShape=shapeFactory.getShape(targetClassName);targetShape.draw();}
這樣,當修改調用子類時,只需要修改設定檔即可。當然,對於簡單的原廠模式應用沒必要如此繁瑣
理解了這個,也就不難理解Spring的Ioc技術,Spring的設定檔換成了xml檔案,而且設計比較複雜,調用程式變成了所謂的spring容器,當然這隻是spring設計的基石,上層建築還是很複雜的。