Head First 设计模式 —— 05. 单例模式

2021-01-08  本文已影响0人  满赋诸机

全局变量的缺点

如果将对象赋值给一个全局变量,那么必须在程序一开始就创建好对象 P170

思考题

Choc-O-Holic 公司使用如下工业强度巧克力锅炉控制器

public class ChocolateBoiler {
    private boolean empty;
    private boolean boiled;
    
    public ChocolateBoiler() {
        empty = true;
        boiled = false;
    }
    
    public void fill() {
        if (isEmpty()) {
            empty = false;
            boiled = false;
            // 在锅炉内填满巧克力和牛奶的混合物
        }
    }
    
    public void drain() {
        if (!isEmpty() && isBoiled()) {
            // 排出煮沸的巧克力和牛奶
            empty = true;
        }
    }
    
    public void boil() {
        if (!isEmpty() && ! isBoiled()) {
            // 将炉内物煮沸
            boiled = true;
        }
    }
    
    public boolean isEmpty() {
        return empty;
    }
    
    public boolnea isBoiled() {
        return boiled;
    }
}

思考题

Choc-O-Holic 公司在有意识地防止不好的事情发生,你不这么认为吗?你可能会担心,如果同时存在两个 ChocolateBoiler(巧克力锅炉)实例,可能将会发生很糟糕的事情。
万一同时有多于一个的 ChocolateBoiler(巧克力锅炉)实例存在,可能发生哪些很糟糕的事呢? P176

单例模式

确保一个类只有一个实例,并提供一个全局访问点。 P177

05. 单例模式

思考题

所有变量和方法都定义为静态的,直接把类当作一个单例,这样如何? P184

思考题

多个类加载器有机会创建各自的单例实例,如何避免? P184

单例模式的七种方法

推荐使用静态内部类和枚举方式

饿汉式 P181
public class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
饿汉式(变种)
public class Singleton {
    private static Singleton INSTANCE;
    
    static {
        INSTANCE = new Singleton();
    }
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

【扩展】 静态代码块初始化静态变量最好放在定义变量之后,否则会在执行定义变量可能出现被覆盖的问题(如果定义有赋值(包括 null),则会覆盖静态代码块已赋的值)。
原因:静态域的初始化和静态代码块的执行会从上到下依次执行。
如下写法最终会得到 null

public class Singleton {
    static {
        INSTANCE = new Singleton();
    }
    
    private static Singleton INSTANCE = null;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
懒汉式 P176
public class Singleton {
    private static Singleton INSTANCE = null;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}
懒汉式(变种) P180
public class Singleton {
    private static Singleton INSTANCE = null;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}
双重校验锁 P182
public class Singleton {
    private volatile static Singleton INSTANCE = null;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}
静态内部类
public class Singleton {
    private static class SingletonHolder {
        private final static Singleton INSTANCE = new Singleton();
    }

    private Singleton() {}

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
枚举
public enum Singleton {
    INSTANCE
}
上一篇 下一篇

猜你喜欢

热点阅读