1. 程式人生 > 其它 >通用(超級)工廠的建立以及通過工廠控制物件的建立次數

通用(超級)工廠的建立以及通過工廠控制物件的建立次數

技術標籤:筆記思考java設計模式spring

通用工廠

Java的核心是反射和介面,通用工廠不同於靜態工廠,具有高可用性。

public class BeanFactory {
    private BeanFactory(){};

    public static Object getObject(String beanName) {
        Object obj = null;
        //1,反射載入class檔案,無需導包
        try {
            Class<?>clazz = Class.forName(beanName);
//        2,例項化物件

            obj = clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
//        3,返回物件
        return obj;

    }
//    通過class檔案來獲取物件
    public static <T> T getObject(Class<T> clazz){
        T ret =null;
        try {
            ret=(T)clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }
}

這是簡單的通用工廠,如果要增加比較複雜的功能,比如說控制物件的建立次數,(有些物件,比如說UseService只需要一個即可,返回的是一個單例)。

什麼是單例:就是通過建立物件的方法建立的物件,一直是原來的那個物件,最直接的體現就是物件的地址相同。

什麼是多例:就是每次建立的物件都不一樣,體現在每次建立的物件的地址不同。

物件建立只有一次或者無數次!!!

通過工廠控制物件的建立次數

那麼將工廠進行修改,此時不太需要靜態方法,直接new更好,體現了工廠是重量級資源,修改程式碼如下:

package factory;
import java.util.HashMap;
import java.util.Map;
public class BeanFactory {
//    用來儲存已經建立過的物件
    private Map<String,Object>maps;
//    工廠建立的同時,內建map生效
    public BeanFactory(){
        maps = new HashMap<>();
    };

    protected   Object getObject(String beanName) throws Exception {
        Object obj = null;
        //1,反射載入class檔案,無需導包
            Class<?>clazz = Class.forName(beanName);
//        2,例項化物件
            obj = clazz.getDeclaredConstructor().newInstance();
//        3,返回物件
        return obj;

    }
//    通過class檔案來獲取物件
    protected  Object getObject(Class clazz) throws Exception {
        return clazz.getDeclaredConstructor().newInstance();
    }
    protected boolean ifExist(Class clazz){
        return maps.containsKey(clazz.getName());
    }
    protected Object getExistObject(String name){
        return maps.get(name);
    }

    /**
     * 因為此時工廠要控制物件的建立次數,所以,其他的建立物件的方法必須私有化
     * @param clazz  需要傳入的class物件
     * @param isSingleton 是否該物件只需要一個
     * @return 返回物件
     * @throws Exception 產生的異常
     */
    public Object getObject(Class clazz,boolean isSingleton) throws Exception {
        Object ret=null;
        String name = clazz.getName();
//        if object already exists
        if(this.ifExist(clazz)){
            if(isSingleton){
                ret= this.getExistObject(name);
            }else{
                ret = this.getObject(clazz);
            }
        }else{
            if(isSingleton){
                ret = this.getObject(clazz);
                maps.put(name,ret);
            }else{
                ret = this.getObject(clazz);
            }
        }
        return ret;
    }
    
    //此時需要多個getObject方法的過載,在這裡就不一一列舉寫了。
    public Object getObjectDefault(Class clazz) throws Exception {
       return this.getObject(clazz,true);
    }
}

程式碼測試結果如下:

 BeanFactory factory = new BeanFactory();

        System.out.println(factory.getObjectDefault(User.class));
        System.out.println(factory.getObject(User.class,true));
        System.out.println(factory.getObject(User.class,false));

結果:

可以進行改進的地方:有一個通過過載的方法-通過名稱來得到物件。因為要想反射建立類,該名稱必須是全稱,而全稱非常長,書寫不方便,所以我們可以應用properties檔案來對名稱進行簡化。

通過Properties類(特殊的map,key=String=value),或者是ResourceBundle類。來對類名稱進行簡化處理。

這個工廠的建立是不是很熟悉,對,就是spring的超級工廠的一些簡化,這個簡化工廠已經實現了工廠的一部分核心功能。