1. 程式人生 > >容器工廠(原型&單例)

容器工廠(原型&單例)

col ima hash ssl init image 判斷 catch sax解析

上一篇講的是容器工廠的原型。

我們可以不必通過new關鍵之創建實例,可以直接取容器裏面的實例。

我們可以發現,在對比他們的地址值的時候,他們是相同的為true。

如果我們需要的是不一樣的呢。也就是有一些特殊的操作需要到的是單例地址。

下面讓我們看看如何創建一個可以隨意切換原型&單例的容器工廠吧。

我們在上一篇原型的容器工廠上稍微做一下改造就OK了!

添加一個描述bean的類,封裝了配置文件bean的類

public class Definition {
    //bean的唯一標識
    private String id;
    //bean的完整類名
    private String className;
    
//bean的創建方式 private String scope = "singleton"; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; }
public String getScope() { return scope;   } public void setScope(String scope) { this.scope = scope; } }

第二,我們需要在容器工廠的類裏面做出稍稍的改動。

如下:

public class ContainerFactoryTwo {
    //單例的容器(Singleton)
    private static Map<String,Object> singleton = new HashMap<String,Object>();

    
//原型的容器(prototype) private static Map<String,Definition> prototype = new HashMap<String,Definition>(); //初始化 public ContainerFactoryTwo(String resourcePath){ initPrototype(resourcePath); initSingleton(); } public void initPrototype(String resourcePath){ //創建SAX解析器 SAXReader reader = new SAXReader(); try { Document document = reader.read(Thread.currentThread().getContextClassLoader().getResourceAsStream(resourcePath)); Element root = document.getRootElement(); List<Element> list = root.elements(); for (Element e:list){ String id = e.attributeValue("id"); String className = e.attributeValue("class"); String scope = e.attributeValue("scope"); //構建bean的定義 Definition def = new Definition(); def.setId(id); def.setClassName(className); if(scope!=null){ def.setScope(scope); } prototype.put(id,def); } } catch (Exception e) { throw new RuntimeException(e); } } /** * 初始化單利容器 */ private void initSingleton(){ //遍歷prototype裏面的值做出判斷 for (String key : prototype.keySet()) { Definition def = prototype.get(key); //如果是判斷是否是singleton if("singleton".equals(def.getScope())){ try { //將實例化對象保存到singleton的map裏 singleton.put(key, Class.forName(def.getClassName()).newInstance()); } catch (Exception e) { throw new RuntimeException(e); } } } } public Object getBean(String name){ return getContainerBean(name); } public <T> T getBean(String name, Class<T> clazz){ return (T)getContainerBean(name); } private Object getContainerBean(String name){ //獲取作用域屬性 String scope = prototype.get(name).getScope(); try { //三目運算,singleton在scope裏面?是的話就之前前者(K對應的已經是一個Object對象)否則執行後者,通過類加載返回一個對象 return ("singleton".equals(scope))?singleton.get(name): Class.forName(prototype.get(name).getClassName()).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } }

測試:

public class Main {
    public static void main(String[] args) {
        //創建工廠
        ContainerFactoryTwo factory = new ContainerFactoryTwo("beans.xml");

        Phone phone1 = factory.getBean("OppoPhone", Phone.class);//singleton
        Phone phone2 = factory.getBean("OppoPhone", Phone.class);//singleton

        Pad pad1 = (Pad) factory.getBean("OppoPad", Pad.class);//prototype
        Pad pad2 = (Pad) factory.getBean("OppoPad", Pad.class);//prototype
        System.out.println(phone1==phone2);
        System.out.println(pad1==pad2);
        //phone1.call();
    }
}

結果為:

true

false

註意:在XML文件裏面的scope

技術分享圖片

決定單例或者是原型容器在於Map

容器工廠(原型&單例)