[轉]反射在工廠模式上的應用

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,實現了很好的封裝。


發佈了10 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章