1. 程式人生 > 其它 >設計模式之美--單例模式

設計模式之美--單例模式

單例模式的幾個實現方式:實現遞增id生成器

  1. 餓漢式
/**
 * 餓漢式(不支援延遲載入)
 * @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();
    }
}
  1. 懶漢式
/**
 * 懶漢式(延遲載入,例項真正使用的時候才去初始化)
 * 如果例項載入耗費資源比較多,當資源不夠時會報錯。
 * 理解:按照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();
    }
}
  1. 雙重檢測
/**
 * 雙重檢測(支援延遲載入,也支援高併發)
 * 存在指令重排序問題,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();
    }
}
  1. 靜態內部類
/**
 * 靜態內部類(類似餓漢式,但支援延遲載入)
 * 當 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();
    }
}
  1. 列舉
/**
 * 列舉
 * @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);
    }
}

單例模式的弊端

  1. 隱藏類之間的依賴關係
  2. 影響程式碼的擴充套件性
  3. 影響程式碼的可測試性
  4. 不支援包含引數的建構函式