Design pattern ——singleton pattern(單例深入研究)

Talk is cheap  Show me the code

個人學習筆記--僅供參考

註冊式單例

註冊式單例又稱爲登記式單例,就是將每一個實例都登記到某一個地方,使用唯一的標
識獲取實例

註冊式單例有兩種寫法:一種爲容器緩存,一種爲枚舉登記

枚舉

package pattern;
/**
 * 註冊式單例又稱爲登記式單例,就是將每一個實例都登記到某一個地方,使用唯一的標
識獲取實例。註冊式單例有兩種寫法:一種爲容器緩存,一種爲枚舉登記。先來看枚舉
式單例的寫法,來看代碼
 * @author qsnp236
 *
 */
public enum EnumSingleton{
	// 餓漢
	HUNGARY("hungary"),
	// 懶漢
	LAZY("lazy"),
	// 內部類
	INNERCLASS("inner_class");

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
    EnumSingleton(String name){
    	this.name=name;
    }
	public static EnumSingleton getInstance(String desc) {
		for (EnumSingleton configType : EnumSingleton.values()){
			if (configType.getName().equals(desc)){
			   return configType;
			}
	     }
			throw new IllegalArgumentException("無法轉化爲對應的enum類型,原因是未知描述信息: " + desc);
	}

}

測試類

package pattern;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class EnumSingletonTest {

	public static void main(String[] args) {

		EnumSingleton s1=EnumSingleton.getInstance("lazy");
		
		FileOutputStream fos;
		try {
			fos = new FileOutputStream("EnumSingleton.obj");
			ObjectOutputStream os= new ObjectOutputStream(fos);
			os.writeObject(s1);
			os.flush();
			os.close();
			FileInputStream fis= new FileInputStream("EnumSingleton.obj");
			ObjectInputStream ois= new ObjectInputStream(fis);
			EnumSingleton s2=(EnumSingleton) ois.readObject();
			ois.close();
			System.out.println(s1);
			System.out.println(s2);
			System.out.println(s1.getName());
			System.out.println(s2.getName());
			System.out.println(s1==s2);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

測試結果

LAZY
LAZY
lazy
lazy
true

 底層代碼

static
{
INSTANCE = new EnumSingleton("INSTANCE", 0);
$VALUES = (new EnumSingleton[] {
INSTANCE
});
}

原來,枚舉式單例在靜態代碼塊中就給INSTANCE 進行了賦值,是餓漢式單例的實現,

序列化和反序列化中,我們發現枚舉類型其實通過類名和Class 對象類找到一個唯一的枚舉對象。因此,枚舉對
象不可能被類加載器加載多次,反射中,在newInstance()方法中做了強制性的判斷,如果修飾符是Modifier.ENUM 枚舉類型,
直接拋出異常

 

接下來看註冊式單例還有另一種寫法,容器緩存的寫法,創建ContainerSingleton 類

package pattern;

import java.io.Serializable;
import java.nio.file.SecureDirectoryStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 容器式寫法適用於創建實例非常多的情況,便於管理。但是,是非線程安全的。比如spring IOC 容器
 * 
 * @author qsnp236
 *
 */
public class ContainerSingleton implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private ContainerSingleton() {
	}

	private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();

	public static Object getBean(String className) {
		synchronized (ioc) {
			if (!ioc.containsKey(className)) {
				Object obj = null;
				try {
					Class<?> clazz = Class.forName(className);
					obj = clazz.newInstance();
					ioc.put(className, obj);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return obj;

			} else {
				return ioc.get(className);
			}

		}

	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章