设计模式-单例

上周开发的时候需要做一个校验用户姓名格式的类,因为提供的是公共功能,类似于工具类,所以最好拿来就能用。内部逻辑大体如下所示:

public class NameValidateUtil {
    
    // 校验姓名格式是否满足要求
    public boolean validateName (String name) {
        // 判断是不是汉字的姓名
        if (isChineseName(name)) {
            // 是汉字,就用汉字的校验逻辑
            return validateChineseName(name);
        } else {
            // 否则是英文,用英文的校验逻辑
            return validateEnglishName(name);
        }
    }
    
    private boolean validateEnglishName(String name) {
        // 此处省略校验逻辑
        return true;
    }

    private boolean validateChineseName(String name) {
        // 此处省略校验逻辑
        return true;
    }

    private boolean isChineseName(String name) {
        // 此处省略判断逻辑
        return false;
    }
}  

可以看到,校验逻辑比较多,不适合放在一个方法里,如果给每一个方法都加上static也可以做到拿来即用,但这样的设计不够优雅。既然不适合直接用静态的方式,那么很容易就会想到可以用单例模式来实现。其实说实话,在这之前虽然博主也将23中设计模式了解过一遍,但是大多未在项目中实际操作过,所以对设计模式使用的必然性缺少认识,而这一次便让我切身体会到了适合单例模式的使用场景。如上所述的,如果一个类提供的是公共的功能,且不方便给其方法设置成static静态的,那么就可以使用单例模式来实现

对于单例模式,园友们应该都知道老生常谈的那两种:饿汉式和懒汉式。基本的实现方式大家都清楚,此处就不贴了。饿汉式虽然不会出现线程安全的情况,但除非某些特殊场景,一般都不使用。而一般的懒汉式,对于线程安全的解决办法是双重检查锁(dubbo-check),如下所示:

public class NameValidateUtil {
    // 私有化构造器,让外部无法对该类实例化
    private NameValidateUtil(){}

    private static NameValidateUtil nameValidateUtil;
    
    public static NameValidateUtil getSingleton(){
        if (nameValidateUtil == null) {
            synchronized (NameValidateUtil.class) {
                if (nameValidateUtil == null) {
                    nameValidateUtil = new NameValidateUtil();
                }
            }
        }
        return nameValidateUtil;
    }
}

但由于JVM的内存模型中允许指令重排序,即在

 nameValidateUtil = new NameValidateUtil();

这句的三步(a.分配内存地址;b.初始化;c.将内存地址传给引用)中,b与c可能会c先执行,b后执行,这样在高并发的情况下,就可能会出现某个线程获取到了未完成初始化的对象的情况。为避免此情况,可以通过给nameValidateUtil加volatile关键字的方式来避免重排序。

或者使用静态内部类的方式(静态内部类是在使用的时候才会初始化,且JVM能保证只初始化一次),代码如下所示:

public class NameValidateUtil {
    // 私有化构造器,让外部无法对该类实例化
    private NameValidateUtil(){}

    private static NameValidateUtil nameValidateUtil;

    public static NameValidateUtil getSingleton(){
        return InnerNameValidateUtil.innerValidate;
    }
    
    private static class InnerNameValidateUtil {
        static NameValidateUtil innerValidate = new NameValidateUtil();
    }
}

九月份加班成魔,学习进度严重落后,十月份应该就回归正轨了,务必抓紧时间学习!  

 

posted on 2019-09-28 23:56  淡墨痕  阅读(282)  评论(3编辑  收藏  举报