小學生學習設計模式之單例模式
一、什麼是單例模式
單例模式(Singleton Pattern),涉及一個單一的類,該類負責建立自己的物件,確保只有單個物件建立,提供一種訪問其唯一的物件的方式,可以直接訪問,不需要例項該類的物件。
單例類只有一個例項,外部不能例項單例類,構造方法隱藏 單例類必須自己建立自己的唯一例項 單例類必須提供這一例項
二、實現
public class Singleton {
/**
* 唯一例項
*/
private static Singleton instance = new Singleton();
/**
* 構造方法隱藏,無法例項
*/
private Singleton(){}
/**
* 提供外部訪問唯一例項的方法
* @return
*/
public static Singleton getInstance(){
return instance;
}
public void message(){
System.out.println("This is Singleton Patterm");
}
}
複製程式碼
public class SingletonPattermDemo {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton singleton = Singleton.getInstance();
System.out.println(singleton == instance);
instance.message();
}
}
/*
* true
* This is Singleton Patterm
*/
複製程式碼
三、單例模式的幾種實現方法
1. 懶漢式,執行緒不安全
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
return instance = instance != null?instance:new Singleton();
}
}
複製程式碼
2. 懶漢式,執行緒安全
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
return instance = instance != null?instance:new Singleton();
}
}
複製程式碼
3. 餓漢式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
複製程式碼
4. 雙檢鎖/雙重校驗鎖(DCL,double-checked locking)
public class Singleton {
private volatile static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
複製程式碼
5. 靜態內部類
public class Singleton {
private static class SingletonInstance{
private static final Singleton instance = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonInstance.instance;
}
}
複製程式碼
6. 登記式
public class Singleton implements Serializable{
private static Map<String,Object> map;
static{
map = new ConcurrentHashMap<>();
map.put(Singleton.class.getName(),new Singleton());
}
private Singleton(){
System.out.println(Singleton.class.getName());
}
public static final Object getInstance(String name){
if (name == null){
name = Singleton.class.getName();
}
if(map.get(name) == null){
try {
map.put(name,Class.forName(name).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
return map.get(name);
}
}
複製程式碼
7. 列舉(推薦)
public enum Singleton{
INSTANCE;
}
複製程式碼
四、破解單例模式
1. 通過反射破解單例(列舉除外)
public class SingletonPattermDemo {
public static void main(String[] args) throws Exception{
Class cla = Class.forName("cn.pzaily.Singleton");
Constructor constructor = cla.getDeclaredConstructor(null);
constructor.setAccessible(true);
Singleton singleton1 = (Singleton) constructor.newInstance();
Singleton singleton2 = (Singleton) constructor.newInstance();
System.out.println(singleton1 == singleton2);
}
}
複製程式碼
解決辦法:
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton(){
//在構造器中加個邏輯判斷,多次呼叫丟擲異常
if(instance != null){
throw new RuntimeException();
}
}
public static final Singleton getInstance(){
return instance;
}
}
複製程式碼
2. 通過反序列化機制破解單例(列舉除外)
public class SingletonPattermDemo {
public static void main(String[] args) throws Exception {
String path = "xxx";
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
Singleton instance3 = null;
try(FileOutputStream fileOutputStream = new FileOutputStream(path);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
FileInputStream fileInputStream = new FileInputStream(path);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
){
objectOutputStream.writeObject(instance1);
instance3 = (Singleton) objectInputStream.readObject();
}catch (Exception e){
e.printStackTrace();
}
System.out.println(instance1 == instance3);
System.out.println(instance1 == instance2);
}
}
複製程式碼
解決辦法
public class Singleton implements Serializable{
private static final Singleton instance = new Singleton();
private Singleton(){
if(instance != null){
throw new RuntimeException();
}
}
public static final Singleton getInstance(){
return instance;
}
//反序列化定義該方法,則不需要建立新物件
private Object readResolve() throws ObjectStreamException{
return instance;
}
}
複製程式碼
本文使用 mdnice 排版