GOF设计模式之单例模式

2018-07-29  本文已影响0人  zhrowable

定义

单例模式(Singleton Pattern)的定义如下:Ensure a class only has one instance, and provide a global point of access to it(确保某一个类只有一个实例,并且提供一个全局访问点来访问此实例)。在JVM应用中,单例模式表现为一个类在JVM中只有一个实例。一个相对合理的类图如下:

sg-1

使用场景

在JDK中典型的真实例子如下:

适用性

单例模式的优势

单例模式的劣势

实现方式

懒汉方式

懒汉方式的关键字在于"懒",也就是懒加载(Lazy Load),一个很常见的使用方式就是双重检查锁定(Double-Check Locking):

public class Singleton {

    private static volatile Singleton INSTANCE = null;
    
    private Singleton(){

    }

    public static Singleton getInstance(){
        if (null == INSTANCE){
            synchronized (Singleton.class){
                if (null == INSTANCE){
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

饿汉方式

饿汉方式的实现相对简单:

public class Singleton {

    private static volatile Singleton INSTANCE = new Singleton();

    private Singleton(){

    }

    public static Singleton getInstance(){
        return INSTANCE;
    }
}

静态内部类方式

使用静态内部类方式的好处是既可以实现延迟加载,又可以保证线程安全,它的实现如下:

public class Singleton {

    private Singleton(){

    }
    
    private static class InterClassHolder{
        private final static Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance(){
        return InterClassHolder.INSTANCE;
    }
}

最佳实践-单元素枚举方式

《Effective Java》第2版中指出:单元素枚举类型是实现单例的最佳方式。这是因为,前面说到的三种实现方式都可以通过反射改变类的行为,但是枚举类型可以避免这个问题。建议在所有需要使用到单例模式的情况下直接使用单元素枚举方式实现单例:

public enum Singleton {

    INSTANCE;

    public void sayHello() {

    }
}

使用方式:Singleton.INSTANCE.sayHallo()

故事

Doge是公司里一个核心项目的开发组长,手下有十多个组员分别负责开发项目的不同模块。

sg-2 sg-3

Doge展示了一个日期工具类和它的使用情况:

public class DateUtils {

    public static String format(LocalDateTime target,String pattern){
        return DateTimeFormatter.ofPattern(pattern).format(target);
    }

    public LocalDateTime parse(String target,String pattern){
        return LocalDateTime.parse(target, DateTimeFormatter.ofPattern(pattern));
    }
}

//调用情况
DateUtils.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
LocalDateTime target = new DateUtils().parse("2018-7-29 12:12:30","yyyy-MM-dd HH:mm:ss");
sg-3

小黑贴了一下重写的工具类:

public enum DateUtils {

    SINGLETON;

    private static final Map<String, DateTimeFormatter> FORMATTER_CACHE = new HashMap<>();

    public String format(LocalDateTime target, String pattern) {
        return getOrCreateFormatter(pattern).format(target);
    }

    public LocalDateTime parse(String target, String pattern) {
        return LocalDateTime.parse(target, getOrCreateFormatter(pattern));
    }


    private DateTimeFormatter getOrCreateFormatter(String pattern) {
        DateTimeFormatter formatter;
        if (FORMATTER_CACHE.containsKey(pattern)) {
            formatter = FORMATTER_CACHE.get(pattern);
        } else {
            formatter = DateTimeFormatter.ofPattern(pattern);
            FORMATTER_CACHE.put(pattern, formatter);
        }
        return formatter;
    }
}

//调用
DateUtils.SINGLETON.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
LocalDateTime target = DateUtils.SINGLETON.parse("2018-7-29 12:12:30", "yyyy-MM-dd HH:mm:ss");
sg-3

Doge拷贝了小黑的工具类代码,并且仿照这个类的逻辑完成了其他工具类的代码重构。

(本文完)

上一篇下一篇

猜你喜欢

热点阅读