設計模式之美--單例模式
阿新 • • 發佈:2022-12-13
單例模式的幾個實現方式:實現遞增id生成器
- 餓漢式
/** * 餓漢式(不支援延遲載入) * @author lq * @version : IdGenerator.java, v 0.1 2022年12月13日 10:19 lq Exp $ */ public class IdGenerator { //long型別靜態變數和成員變數預設值為0 private AtomicLong id = new AtomicLong(); private static final IdGenerator instance = new IdGenerator(); private IdGenerator(){ } public static IdGenerator getInstance() { return instance; } public long getId() { return id.incrementAndGet(); } }
- 懶漢式
/** * 懶漢式(延遲載入,例項真正使用的時候才去初始化) * 如果例項載入耗費資源比較多,當資源不夠時會報錯。 * 理解:按照fail-fast原則,如果有問題應該儘早暴露出來去解決。 * 所以在專案啟動時,就應該載入這些資源,如果資源不夠,觸發報警機制去解決問題 * * 缺點:因為加了同步鎖 synchronized 所以如果這種工具使用程度高的話,是有效能瓶頸的。 * @author lq * @version : IdGeneratorLazy.java, v 0.1 2022年12月13日 10:30 lq Exp $ */ public class IdGeneratorLazy { private AtomicLong id = new AtomicLong(); private static IdGeneratorLazy instance; private IdGeneratorLazy() { } public static synchronized IdGeneratorLazy getInstance() { if (instance == null) { instance = new IdGeneratorLazy(); } return instance; } public long getId() { return id.incrementAndGet(); } }
- 雙重檢測
/** * 雙重檢測(支援延遲載入,也支援高併發) * 存在指令重排序問題,instance = new IdGeneratorDoubleLock(); * 可以給instance 加上 volatile 關鍵字禁止指令重排序 * @author lq * @version : IdGeneratorDoubleLock.java, v 0.1 2022年12月13日 10:43 lq Exp $ */ public class IdGeneratorDoubleLock { private AtomicLong id = new AtomicLong(); private static volatile IdGeneratorDoubleLock instance; private IdGeneratorDoubleLock() { } public static IdGeneratorDoubleLock getInstance() { if (instance == null) { synchronized (IdGeneratorDoubleLock.class) { if (instance == null) { instance = new IdGeneratorDoubleLock(); } } } return instance; } public long getId() { return id.incrementAndGet(); } }
- 靜態內部類
/**
* 靜態內部類(類似餓漢式,但支援延遲載入)
* 當 IdGeneratorStaticInner 被載入時,內部類不會被載入,只有當getInstance()被呼叫時才會被載入;
* @author lq
* @version : IdGeneratorStaticInner.java, v 0.1 2022年12月13日 10:54 lq Exp $
*/
public class IdGeneratorStaticInner {
private AtomicLong id = new AtomicLong();
private IdGeneratorStaticInner() {
}
private static class SingletonHolder {
private static final IdGeneratorStaticInner instance = new IdGeneratorStaticInner();
}
public static IdGeneratorStaticInner getInstance() {
return SingletonHolder.instance;
}
public long getId() {
return id.incrementAndGet();
}
}
- 列舉
/**
* 列舉
* @author lq
* @version : IdGeneratorEnum.java, v 0.1 2022年12月13日 11:10 lq Exp $
*/
public enum IdGeneratorEnum {
INSTANCE;
private AtomicLong id = new AtomicLong();
public long getId() {
return id.incrementAndGet();
}
}
單例模式的應用舉例:日誌工具類
/**
* @author lq
* @version : Logger.java, v 0.1 2022年12月13日 11:12 lq Exp $
*/
public class Logger {
private FileWriter writer;
private static final Logger instance = new Logger();
private Logger() {
File file = new File("/log.txt");
try {
writer = new FileWriter(file, true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Logger getInstance() {
return instance;
}
public void log(String message) throws IOException {
writer.write(message);
}
}
單例模式的弊端
- 隱藏類之間的依賴關係
- 影響程式碼的擴充套件性
- 影響程式碼的可測試性
- 不支援包含引數的建構函式