1.前言
之前寫過一篇設計模式之簡單工廠(Factory method),在這篇文章的“7.可配置的簡單工廠實例”中,客戶端沒有傳入參數,這是因爲在factory中已經定義了需要讀取的配置文件。但是這樣有個缺點就是靈活性不夠,必須明確指定需要讀取配置文件中的某一項,比如上面就定義了必須讀取的是配置文件中的ImplClass=edu.sjtu.erplab.yanmo.simplefactory.Impl2這一個條目,假設配置文件中有多個條目,我們想要通過客戶端傳入一個簡單的參數ImplClass來動態調用,那麼該實例是不能完成。
2.正文
2.1利用反射機制在客戶端傳入具體的"包.類名"動態創建實例
首先定義一個水果接口Fruit,裏面有一個eat的方法
Fruit.java
package edu.sjtu.erplab.reflect; public interface Fruit { public void eat(); }
然後定義兩類水果Apple和Orange繼承Fruit接口
Apple.java
package edu.sjtu.erplab.reflect; public class Apple implements Fruit { @Override public void eat() { System.out.println("吃蘋果"); } }
Orange.java
package edu.sjtu.erplab.reflect; public class Orange implements Fruit { @Override public void eat() { System.out.println("吃橘子"); } }
Factory.java
package edu.sjtu.erplab.reflect; public class Factory { public static Fruit getInstance(String className) { Fruit fruit=null; try { fruit=(Fruit)Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); } return fruit; } }
最後在客戶端中通過傳入具體的類名來動態創建水果實例
FacotryDemo1.java
package edu.sjtu.erplab.reflect; public class FacotryDemo1 { public static void main(String[] args) { //通過工廠類去的接口實例,傳入完整的包.類名。 Fruit f=null; f=Factory.getInstance("edu.sjtu.erplab.reflect.Apple"); f.eat(); f=Factory.getInstance("edu.sjtu.erplab.reflect.Orange"); f.eat(); } }
第一次傳入的是Apple的類名,第二次傳入的是Orange的雷鳴,所以兩次運行eat方法結果是
吃蘋果
吃橘子
2.2結合配置文件動態創建實例
以上操作代碼雖然可以通過反射取得接口的實例,但是在操作的時候需要傳入完整的包.類名稱,而且用戶也無法知道一個接口有多少個可以使用的子類,所以此時可以通過屬性文件的形式配置所要的子類信息。
在接口類所在包下創建一個Fruit.properties文件,文件內容爲:
apple=edu.sjtu.erplab.reflect.Apple
orange=edu.sjtu.erplab.reflect.Orange
在屬性文件中用簡單的apple和orange來表示完整的包.類名稱,這樣在使用時直接通過屬性名稱即可,不再需要一長串包.類名稱。
要使用屬性文件,我們需要創建屬性操作類,具體實現如下:
package edu.sjtu.erplab.reflect; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class Init { public static Properties getPro() { Properties pro=new Properties(); InputStream in=null; try { in=Init.class.getResourceAsStream("Fruit.properties");//從此類所在的包下取資源 pro.load(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ try{ in.close(); }catch(IOException e){ e.printStackTrace(); } } return pro; } }
這個類用於讀取該類所在的包下的配置文件Fruit.properties,並返回具體的配置文件中的內容。
然後再客戶端中我們只需要通過配置文件操作類獲取配置文件,並傳入屬性名稱即可,代碼實例如下
package edu.sjtu.erplab.reflect; import java.util.Properties; public class FactoryDemo2 { public static void main(String args[]) { Properties pro=Init.getPro(); Fruit f=null; //使用反射創建對象實例 f=Factory.getInstance(pro.getProperty("apple")); f.eat(); f=Factory.getInstance(pro.getProperty("orange")); f.eat(); } }
可以看到這裏我們只需要往工廠方法中傳入pro.getProperty("apple")即可,而pro.getProperty("apple")表示讀取配置文件中key爲apple所對應的value,也就是
edu.sjtu.erplab.reflect.Apple。在這裏客戶只需要知道apple而不需要知道edu.sjtu.erplab.reflect.Apple,實現了很好的封裝。